File manager - Edit - /home/jardides/www/Jardi-design/images/administrator/vendor.tar
Back
composer/autoload_psr4.php 0000604 00000000330 15247143455 0011666 0 ustar 00 <?php // autoload_psr4.php @generated by Composer $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( 'Symfony\\Component\\Yaml\\' => array($vendorDir . '/symfony/yaml'), ); composer/ClassLoader.php 0000604 00000032213 15247143455 0011307 0 ustar 00 <?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 http://www.php-fig.org/psr/psr-0/ * @see http://www.php-fig.org/psr/psr-4/ */ class ClassLoader { // PSR-4 private $prefixLengthsPsr4 = array(); private $prefixDirsPsr4 = array(); private $fallbackDirsPsr4 = array(); // PSR-0 private $prefixesPsr0 = array(); private $fallbackDirsPsr0 = array(); private $useIncludePath = false; private $classMap = array(); private $classMapAuthoritative = false; private $missingClasses = array(); private $apcuPrefix; public function getPrefixes() { if (!empty($this->prefixesPsr0)) { return call_user_func_array('array_merge', $this->prefixesPsr0); } return array(); } public function getPrefixesPsr4() { return $this->prefixDirsPsr4; } public function getFallbackDirs() { return $this->fallbackDirsPsr0; } public function getFallbackDirsPsr4() { return $this->fallbackDirsPsr4; } public function getClassMap() { return $this->classMap; } /** * @param array $classMap Class to filename map */ 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 array|string $paths The PSR-0 root directories * @param bool $prepend Whether to prepend the directories */ public function add($prefix, $paths, $prepend = false) { if (!$prefix) { if ($prepend) { $this->fallbackDirsPsr0 = array_merge( (array) $paths, $this->fallbackDirsPsr0 ); } else { $this->fallbackDirsPsr0 = array_merge( $this->fallbackDirsPsr0, (array) $paths ); } return; } $first = $prefix[0]; if (!isset($this->prefixesPsr0[$first][$prefix])) { $this->prefixesPsr0[$first][$prefix] = (array) $paths; return; } if ($prepend) { $this->prefixesPsr0[$first][$prefix] = array_merge( (array) $paths, $this->prefixesPsr0[$first][$prefix] ); } else { $this->prefixesPsr0[$first][$prefix] = array_merge( $this->prefixesPsr0[$first][$prefix], (array) $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 array|string $paths The PSR-4 base directories * @param bool $prepend Whether to prepend the directories * * @throws \InvalidArgumentException */ public function addPsr4($prefix, $paths, $prepend = false) { if (!$prefix) { // Register directories for the root namespace. if ($prepend) { $this->fallbackDirsPsr4 = array_merge( (array) $paths, $this->fallbackDirsPsr4 ); } else { $this->fallbackDirsPsr4 = array_merge( $this->fallbackDirsPsr4, (array) $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] = (array) $paths; } elseif ($prepend) { // Prepend directories for an already registered namespace. $this->prefixDirsPsr4[$prefix] = array_merge( (array) $paths, $this->prefixDirsPsr4[$prefix] ); } else { // Append directories for an already registered namespace. $this->prefixDirsPsr4[$prefix] = array_merge( $this->prefixDirsPsr4[$prefix], (array) $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 array|string $paths The PSR-0 base directories */ 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 array|string $paths The PSR-4 base directories * * @throws \InvalidArgumentException */ 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 */ 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 */ 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 */ public function setApcuPrefix($apcuPrefix) { $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $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 */ public function register($prepend = false) { spl_autoload_register(array($this, 'loadClass'), true, $prepend); } /** * Unregisters this instance as an autoloader. */ public function unregister() { spl_autoload_unregister(array($this, 'loadClass')); } /** * Loads the given class or interface. * * @param string $class The name of the class * @return bool|null True if loaded, null otherwise */ public function loadClass($class) { if ($file = $this->findFile($class)) { includeFile($file); return true; } } /** * 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; } 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])) { foreach ($this->prefixDirsPsr4[$search] as $dir) { $length = $this->prefixLengthsPsr4[$first][$search]; if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) { 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; } } /** * Scope isolated include. * * Prevents access to $this/self from included files. */ function includeFile($file) { include $file; } composer/LICENSE 0000604 00000002056 15247143455 0007411 0 ustar 00 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. composer/autoload_real.php 0000604 00000003342 15247143455 0011727 0 ustar 00 <?php // autoload_real.php @generated by Composer class ComposerAutoloaderInit3cfd72445e0ad28db5332442bcda1e66 { private static $loader; public static function loadClassLoader($class) { if ('Composer\Autoload\ClassLoader' === $class) { require __DIR__ . '/ClassLoader.php'; } } public static function getLoader() { if (null !== self::$loader) { return self::$loader; } spl_autoload_register(array('ComposerAutoloaderInit3cfd72445e0ad28db5332442bcda1e66', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(); spl_autoload_unregister(array('ComposerAutoloaderInit3cfd72445e0ad28db5332442bcda1e66', 'loadClassLoader')); $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); if ($useStaticLoader) { require_once __DIR__ . '/autoload_static.php'; call_user_func(\Composer\Autoload\ComposerStaticInit3cfd72445e0ad28db5332442bcda1e66::getInitializer($loader)); } else { $map = require __DIR__ . '/autoload_namespaces.php'; foreach ($map as $namespace => $path) { $loader->set($namespace, $path); } $map = require __DIR__ . '/autoload_psr4.php'; foreach ($map as $namespace => $path) { $loader->setPsr4($namespace, $path); } $classMap = require __DIR__ . '/autoload_classmap.php'; if ($classMap) { $loader->addClassMap($classMap); } } $loader->register(true); return $loader; } } composer/autoload_static.php 0000604 00000004225 15247143455 0012274 0 ustar 00 <?php // autoload_static.php @generated by Composer namespace Composer\Autoload; class ComposerStaticInit3cfd72445e0ad28db5332442bcda1e66 { public static $prefixLengthsPsr4 = array ( 'S' => array ( 'Symfony\\Component\\Yaml\\' => 23, ), ); public static $prefixDirsPsr4 = array ( 'Symfony\\Component\\Yaml\\' => array ( 0 => __DIR__ . '/..' . '/symfony/yaml', ), ); public static $classMap = array ( 'Symfony\\Component\\Yaml\\Command\\LintCommand' => __DIR__ . '/..' . '/symfony/yaml/Command/LintCommand.php', 'Symfony\\Component\\Yaml\\Dumper' => __DIR__ . '/..' . '/symfony/yaml/Dumper.php', 'Symfony\\Component\\Yaml\\Escaper' => __DIR__ . '/..' . '/symfony/yaml/Escaper.php', 'Symfony\\Component\\Yaml\\Exception\\DumpException' => __DIR__ . '/..' . '/symfony/yaml/Exception/DumpException.php', 'Symfony\\Component\\Yaml\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/yaml/Exception/ExceptionInterface.php', 'Symfony\\Component\\Yaml\\Exception\\ParseException' => __DIR__ . '/..' . '/symfony/yaml/Exception/ParseException.php', 'Symfony\\Component\\Yaml\\Exception\\RuntimeException' => __DIR__ . '/..' . '/symfony/yaml/Exception/RuntimeException.php', 'Symfony\\Component\\Yaml\\Inline' => __DIR__ . '/..' . '/symfony/yaml/Inline.php', 'Symfony\\Component\\Yaml\\Parser' => __DIR__ . '/..' . '/symfony/yaml/Parser.php', 'Symfony\\Component\\Yaml\\Unescaper' => __DIR__ . '/..' . '/symfony/yaml/Unescaper.php', 'Symfony\\Component\\Yaml\\Yaml' => __DIR__ . '/..' . '/symfony/yaml/Yaml.php', ); public static function getInitializer(ClassLoader $loader) { return \Closure::bind(function () use ($loader) { $loader->prefixLengthsPsr4 = ComposerStaticInit3cfd72445e0ad28db5332442bcda1e66::$prefixLengthsPsr4; $loader->prefixDirsPsr4 = ComposerStaticInit3cfd72445e0ad28db5332442bcda1e66::$prefixDirsPsr4; $loader->classMap = ComposerStaticInit3cfd72445e0ad28db5332442bcda1e66::$classMap; }, null, ClassLoader::class); } } composer/installed.php 0000644 00000001334 15247143455 0011076 0 ustar 00 <?php return array( 'root' => array( 'pretty_version' => 'dev-main', 'version' => 'dev-main', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'reference' => '1005f7331037063170ca4f1a6861984f9b932586', 'name' => '__root__', 'dev' => true, ), 'versions' => array( '__root__' => array( 'pretty_version' => 'dev-main', 'version' => 'dev-main', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'reference' => '1005f7331037063170ca4f1a6861984f9b932586', 'dev_requirement' => false, ), ), ); composer/autoload_namespaces.php 0000604 00000000225 15247143455 0013120 0 ustar 00 <?php // autoload_namespaces.php @generated by Composer $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( ); composer/installed.json 0000604 00000003307 15247143455 0011256 0 ustar 00 [ { "name": "symfony/yaml", "version": "v3.2.6", "version_normalized": "3.2.6.0", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", "reference": "093e416ad096355149e265ea2e4cc1f9ee40ab1a" }, "dist": { "type": "zip", "url": "https://api.github.com/repos/symfony/yaml/zipball/093e416ad096355149e265ea2e4cc1f9ee40ab1a", "reference": "093e416ad096355149e265ea2e4cc1f9ee40ab1a", "shasum": "" }, "require": { "php": ">=5.5.9" }, "require-dev": { "symfony/console": "~2.8|~3.0" }, "suggest": { "symfony/console": "For validating YAML files using the lint command" }, "time": "2017-03-07T16:47:02+00:00", "type": "library", "extra": { "branch-alias": { "dev-master": "3.2-dev" } }, "installation-source": "dist", "autoload": { "psr-4": { "Symfony\\Component\\Yaml\\": "" }, "exclude-from-classmap": [ "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { "name": "Fabien Potencier", "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com" } ] composer/InstalledVersions.php 0000644 00000035217 15247143455 0012576 0 ustar 00 <?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` */ class InstalledVersions { /** * @var mixed[]|null * @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}|array{}|null */ private static $installed; /** * @var bool|null */ private static $canGetVendors; /** * @var array[] * @psalm-var array<string, array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: 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 || empty($installed['versions'][$packageName]['dev_requirement']); } } 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($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, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string} */ 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, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: 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, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: 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, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data */ public static function reload($data) { self::$installed = $data; self::$installedByVendor = array(); } /** * @return array[] * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}> */ private static function getInstalled() { if (null === self::$canGetVendors) { self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); } $installed = array(); if (self::$canGetVendors) { foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { if (isset(self::$installedByVendor[$vendorDir])) { $installed[] = self::$installedByVendor[$vendorDir]; } elseif (is_file($vendorDir.'/composer/installed.php')) { $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { self::$installed = $installed[count($installed) - 1]; } } } } if (null === self::$installed) { // only require the installed.php file if this file is loaded from its dumped location, // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 if (substr(__DIR__, -8, 1) !== 'C') { self::$installed = require __DIR__ . '/installed.php'; } else { self::$installed = array(); } } $installed[] = self::$installed; return $installed; } } composer/autoload_classmap.php 0000604 00000002341 15247143455 0012605 0 ustar 00 <?php // autoload_classmap.php @generated by Composer $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( 'Symfony\\Component\\Yaml\\Command\\LintCommand' => $vendorDir . '/symfony/yaml/Command/LintCommand.php', 'Symfony\\Component\\Yaml\\Dumper' => $vendorDir . '/symfony/yaml/Dumper.php', 'Symfony\\Component\\Yaml\\Escaper' => $vendorDir . '/symfony/yaml/Escaper.php', 'Symfony\\Component\\Yaml\\Exception\\DumpException' => $vendorDir . '/symfony/yaml/Exception/DumpException.php', 'Symfony\\Component\\Yaml\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/yaml/Exception/ExceptionInterface.php', 'Symfony\\Component\\Yaml\\Exception\\ParseException' => $vendorDir . '/symfony/yaml/Exception/ParseException.php', 'Symfony\\Component\\Yaml\\Exception\\RuntimeException' => $vendorDir . '/symfony/yaml/Exception/RuntimeException.php', 'Symfony\\Component\\Yaml\\Inline' => $vendorDir . '/symfony/yaml/Inline.php', 'Symfony\\Component\\Yaml\\Parser' => $vendorDir . '/symfony/yaml/Parser.php', 'Symfony\\Component\\Yaml\\Unescaper' => $vendorDir . '/symfony/yaml/Unescaper.php', 'Symfony\\Component\\Yaml\\Yaml' => $vendorDir . '/symfony/yaml/Yaml.php', ); autoload.php 0000604 00000000262 15247143455 0007073 0 ustar 00 <?php // autoload.php @generated by Composer require_once __DIR__ . '/composer/autoload_real.php'; return ComposerAutoloaderInit3cfd72445e0ad28db5332442bcda1e66::getLoader(); symfony/yaml/composer.json 0000604 00000001626 15247160545 0011746 0 ustar 00 { "name": "symfony/yaml", "type": "library", "description": "Symfony Yaml Component", "keywords": [], "homepage": "https://symfony.com", "license": "MIT", "authors": [ { "name": "Fabien Potencier", "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], "require": { "php": ">=5.5.9" }, "require-dev": { "symfony/console": "~2.8|~3.0" }, "suggest": { "symfony/console": "For validating YAML files using the lint command" }, "autoload": { "psr-4": { "Symfony\\Component\\Yaml\\": "" }, "exclude-from-classmap": [ "/Tests/" ] }, "minimum-stability": "dev", "extra": { "branch-alias": { "dev-master": "3.2-dev" } } } symfony/yaml/LICENSE 0000604 00000002051 15247160545 0010222 0 ustar 00 Copyright (c) 2004-2017 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. symfony/yaml/Tests/ParseExceptionTest.php 0000604 00000002003 15247160545 0014616 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Yaml\Tests; use PHPUnit\Framework\TestCase; use Symfony\Component\Yaml\Exception\ParseException; class ParseExceptionTest extends TestCase { public function testGetMessage() { $exception = new ParseException('Error message', 42, 'foo: bar', '/var/www/app/config.yml'); $message = 'Error message in "/var/www/app/config.yml" at line 42 (near "foo: bar")'; $this->assertEquals($message, $exception->getMessage()); } public function testGetMessageWithUnicodeInFilename() { $exception = new ParseException('Error message', 42, 'foo: bar', 'äöü.yml'); $message = 'Error message in "äöü.yml" at line 42 (near "foo: bar")'; $this->assertEquals($message, $exception->getMessage()); } } symfony/yaml/Tests/ParserTest.php 0000604 00000102150 15247160545 0013125 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Yaml\Tests; use PHPUnit\Framework\TestCase; use Symfony\Component\Yaml\Exception\ParseException; use Symfony\Component\Yaml\Yaml; use Symfony\Component\Yaml\Parser; class ParserTest extends TestCase { protected $parser; protected function setUp() { $this->parser = new Parser(); } protected function tearDown() { $this->parser = null; } /** * @dataProvider getDataFormSpecifications */ public function testSpecifications($file, $expected, $yaml, $comment, $deprecated) { $deprecations = array(); if ($deprecated) { set_error_handler(function ($type, $msg) use (&$deprecations) { if (E_USER_DEPRECATED !== $type) { restore_error_handler(); if (class_exists('PHPUnit_Util_ErrorHandler')) { return call_user_func_array('PHPUnit_Util_ErrorHandler::handleError', func_get_args()); } return call_user_func_array('PHPUnit\Util\ErrorHandler::handleError', func_get_args()); } $deprecations[] = $msg; }); } $this->assertEquals($expected, var_export($this->parser->parse($yaml), true), $comment); if ($deprecated) { restore_error_handler(); $this->assertCount(1, $deprecations); $this->assertContains('Using the comma as a group separator for floats is deprecated since version 3.2 and will be removed in 4.0.', $deprecations[0]); } } public function getDataFormSpecifications() { $parser = new Parser(); $path = __DIR__.'/Fixtures'; $tests = array(); $files = $parser->parse(file_get_contents($path.'/index.yml')); foreach ($files as $file) { $yamls = file_get_contents($path.'/'.$file.'.yml'); // split YAMLs documents foreach (preg_split('/^---( %YAML\:1\.0)?/m', $yamls) as $yaml) { if (!$yaml) { continue; } $test = $parser->parse($yaml); if (isset($test['todo']) && $test['todo']) { // TODO } else { eval('$expected = '.trim($test['php']).';'); $tests[] = array($file, var_export($expected, true), $test['yaml'], $test['test'], isset($test['deprecated']) ? $test['deprecated'] : false); } } } return $tests; } public function testTabsInYaml() { // test tabs in YAML $yamls = array( "foo:\n bar", "foo:\n bar", "foo:\n bar", "foo:\n bar", ); foreach ($yamls as $yaml) { try { $content = $this->parser->parse($yaml); $this->fail('YAML files must not contain tabs'); } catch (\Exception $e) { $this->assertInstanceOf('\Exception', $e, 'YAML files must not contain tabs'); $this->assertEquals('A YAML file cannot contain tabs as indentation at line 2 (near "'.strpbrk($yaml, "\t").'").', $e->getMessage(), 'YAML files must not contain tabs'); } } } public function testEndOfTheDocumentMarker() { $yaml = <<<'EOF' --- %YAML:1.0 foo ... EOF; $this->assertEquals('foo', $this->parser->parse($yaml)); } public function getBlockChompingTests() { $tests = array(); $yaml = <<<'EOF' foo: |- one two bar: |- one two EOF; $expected = array( 'foo' => "one\ntwo", 'bar' => "one\ntwo", ); $tests['Literal block chomping strip with single trailing newline'] = array($expected, $yaml); $yaml = <<<'EOF' foo: |- one two bar: |- one two EOF; $expected = array( 'foo' => "one\ntwo", 'bar' => "one\ntwo", ); $tests['Literal block chomping strip with multiple trailing newlines'] = array($expected, $yaml); $yaml = <<<'EOF' {} EOF; $expected = array(); $tests['Literal block chomping strip with multiple trailing newlines after a 1-liner'] = array($expected, $yaml); $yaml = <<<'EOF' foo: |- one two bar: |- one two EOF; $expected = array( 'foo' => "one\ntwo", 'bar' => "one\ntwo", ); $tests['Literal block chomping strip without trailing newline'] = array($expected, $yaml); $yaml = <<<'EOF' foo: | one two bar: | one two EOF; $expected = array( 'foo' => "one\ntwo\n", 'bar' => "one\ntwo\n", ); $tests['Literal block chomping clip with single trailing newline'] = array($expected, $yaml); $yaml = <<<'EOF' foo: | one two bar: | one two EOF; $expected = array( 'foo' => "one\ntwo\n", 'bar' => "one\ntwo\n", ); $tests['Literal block chomping clip with multiple trailing newlines'] = array($expected, $yaml); $yaml = <<<'EOF' foo: - bar: | one two EOF; $expected = array( 'foo' => array( array( 'bar' => "one\n\ntwo", ), ), ); $tests['Literal block chomping clip with embedded blank line inside unindented collection'] = array($expected, $yaml); $yaml = <<<'EOF' foo: | one two bar: | one two EOF; $expected = array( 'foo' => "one\ntwo\n", 'bar' => "one\ntwo", ); $tests['Literal block chomping clip without trailing newline'] = array($expected, $yaml); $yaml = <<<'EOF' foo: |+ one two bar: |+ one two EOF; $expected = array( 'foo' => "one\ntwo\n", 'bar' => "one\ntwo\n", ); $tests['Literal block chomping keep with single trailing newline'] = array($expected, $yaml); $yaml = <<<'EOF' foo: |+ one two bar: |+ one two EOF; $expected = array( 'foo' => "one\ntwo\n\n", 'bar' => "one\ntwo\n\n", ); $tests['Literal block chomping keep with multiple trailing newlines'] = array($expected, $yaml); $yaml = <<<'EOF' foo: |+ one two bar: |+ one two EOF; $expected = array( 'foo' => "one\ntwo\n", 'bar' => "one\ntwo", ); $tests['Literal block chomping keep without trailing newline'] = array($expected, $yaml); $yaml = <<<'EOF' foo: >- one two bar: >- one two EOF; $expected = array( 'foo' => 'one two', 'bar' => 'one two', ); $tests['Folded block chomping strip with single trailing newline'] = array($expected, $yaml); $yaml = <<<'EOF' foo: >- one two bar: >- one two EOF; $expected = array( 'foo' => 'one two', 'bar' => 'one two', ); $tests['Folded block chomping strip with multiple trailing newlines'] = array($expected, $yaml); $yaml = <<<'EOF' foo: >- one two bar: >- one two EOF; $expected = array( 'foo' => 'one two', 'bar' => 'one two', ); $tests['Folded block chomping strip without trailing newline'] = array($expected, $yaml); $yaml = <<<'EOF' foo: > one two bar: > one two EOF; $expected = array( 'foo' => "one two\n", 'bar' => "one two\n", ); $tests['Folded block chomping clip with single trailing newline'] = array($expected, $yaml); $yaml = <<<'EOF' foo: > one two bar: > one two EOF; $expected = array( 'foo' => "one two\n", 'bar' => "one two\n", ); $tests['Folded block chomping clip with multiple trailing newlines'] = array($expected, $yaml); $yaml = <<<'EOF' foo: > one two bar: > one two EOF; $expected = array( 'foo' => "one two\n", 'bar' => 'one two', ); $tests['Folded block chomping clip without trailing newline'] = array($expected, $yaml); $yaml = <<<'EOF' foo: >+ one two bar: >+ one two EOF; $expected = array( 'foo' => "one two\n", 'bar' => "one two\n", ); $tests['Folded block chomping keep with single trailing newline'] = array($expected, $yaml); $yaml = <<<'EOF' foo: >+ one two bar: >+ one two EOF; $expected = array( 'foo' => "one two\n\n", 'bar' => "one two\n\n", ); $tests['Folded block chomping keep with multiple trailing newlines'] = array($expected, $yaml); $yaml = <<<'EOF' foo: >+ one two bar: >+ one two EOF; $expected = array( 'foo' => "one two\n", 'bar' => 'one two', ); $tests['Folded block chomping keep without trailing newline'] = array($expected, $yaml); return $tests; } /** * @dataProvider getBlockChompingTests */ public function testBlockChomping($expected, $yaml) { $this->assertSame($expected, $this->parser->parse($yaml)); } /** * Regression test for issue #7989. * * @see https://github.com/symfony/symfony/issues/7989 */ public function testBlockLiteralWithLeadingNewlines() { $yaml = <<<'EOF' foo: |- bar EOF; $expected = array( 'foo' => "\n\nbar", ); $this->assertSame($expected, $this->parser->parse($yaml)); } public function testObjectSupportEnabled() { $input = <<<'EOF' foo: !php/object:O:30:"Symfony\Component\Yaml\Tests\B":1:{s:1:"b";s:3:"foo";} bar: 1 EOF; $this->assertEquals(array('foo' => new B(), 'bar' => 1), $this->parser->parse($input, Yaml::PARSE_OBJECT), '->parse() is able to parse objects'); } /** * @group legacy */ public function testObjectSupportEnabledPassingTrue() { $input = <<<'EOF' foo: !php/object:O:30:"Symfony\Component\Yaml\Tests\B":1:{s:1:"b";s:3:"foo";} bar: 1 EOF; $this->assertEquals(array('foo' => new B(), 'bar' => 1), $this->parser->parse($input, false, true), '->parse() is able to parse objects'); } /** * @group legacy */ public function testObjectSupportEnabledWithDeprecatedTag() { $input = <<<'EOF' foo: !!php/object:O:30:"Symfony\Component\Yaml\Tests\B":1:{s:1:"b";s:3:"foo";} bar: 1 EOF; $this->assertEquals(array('foo' => new B(), 'bar' => 1), $this->parser->parse($input, Yaml::PARSE_OBJECT), '->parse() is able to parse objects'); } /** * @dataProvider invalidDumpedObjectProvider */ public function testObjectSupportDisabledButNoExceptions($input) { $this->assertEquals(array('foo' => null, 'bar' => 1), $this->parser->parse($input), '->parse() does not parse objects'); } /** * @dataProvider getObjectForMapTests */ public function testObjectForMap($yaml, $expected) { $this->assertEquals($expected, $this->parser->parse($yaml, Yaml::PARSE_OBJECT_FOR_MAP)); } /** * @group legacy * @dataProvider getObjectForMapTests */ public function testObjectForMapEnabledWithMappingUsingBooleanToggles($yaml, $expected) { $this->assertEquals($expected, $this->parser->parse($yaml, false, false, true)); } public function getObjectForMapTests() { $tests = array(); $yaml = <<<'EOF' foo: fiz: [cat] EOF; $expected = new \stdClass(); $expected->foo = new \stdClass(); $expected->foo->fiz = array('cat'); $tests['mapping'] = array($yaml, $expected); $yaml = '{ "foo": "bar", "fiz": "cat" }'; $expected = new \stdClass(); $expected->foo = 'bar'; $expected->fiz = 'cat'; $tests['inline-mapping'] = array($yaml, $expected); $yaml = "foo: bar\nbaz: foobar"; $expected = new \stdClass(); $expected->foo = 'bar'; $expected->baz = 'foobar'; $tests['object-for-map-is-applied-after-parsing'] = array($yaml, $expected); $yaml = <<<'EOT' array: - key: one - key: two EOT; $expected = new \stdClass(); $expected->array = array(); $expected->array[0] = new \stdClass(); $expected->array[0]->key = 'one'; $expected->array[1] = new \stdClass(); $expected->array[1]->key = 'two'; $tests['nest-map-and-sequence'] = array($yaml, $expected); $yaml = <<<'YAML' map: 1: one 2: two YAML; $expected = new \stdClass(); $expected->map = new \stdClass(); $expected->map->{1} = 'one'; $expected->map->{2} = 'two'; $tests['numeric-keys'] = array($yaml, $expected); $yaml = <<<'YAML' map: 0: one 1: two YAML; $expected = new \stdClass(); $expected->map = new \stdClass(); $expected->map->{0} = 'one'; $expected->map->{1} = 'two'; $tests['zero-indexed-numeric-keys'] = array($yaml, $expected); return $tests; } /** * @dataProvider invalidDumpedObjectProvider * @expectedException \Symfony\Component\Yaml\Exception\ParseException */ public function testObjectsSupportDisabledWithExceptions($yaml) { $this->parser->parse($yaml, Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE); } /** * @group legacy * @dataProvider invalidDumpedObjectProvider * @expectedException \Symfony\Component\Yaml\Exception\ParseException */ public function testObjectsSupportDisabledWithExceptionsUsingBooleanToggles($yaml) { $this->parser->parse($yaml, true); } public function invalidDumpedObjectProvider() { $yamlTag = <<<'EOF' foo: !!php/object:O:30:"Symfony\Tests\Component\Yaml\B":1:{s:1:"b";s:3:"foo";} bar: 1 EOF; $localTag = <<<'EOF' foo: !php/object:O:30:"Symfony\Tests\Component\Yaml\B":1:{s:1:"b";s:3:"foo";} bar: 1 EOF; return array( 'yaml-tag' => array($yamlTag), 'local-tag' => array($localTag), ); } /** * @requires extension iconv */ public function testNonUtf8Exception() { $yamls = array( iconv('UTF-8', 'ISO-8859-1', "foo: 'äöüß'"), iconv('UTF-8', 'ISO-8859-15', "euro: '€'"), iconv('UTF-8', 'CP1252', "cp1252: '©ÉÇáñ'"), ); foreach ($yamls as $yaml) { try { $this->parser->parse($yaml); $this->fail('charsets other than UTF-8 are rejected.'); } catch (\Exception $e) { $this->assertInstanceOf('Symfony\Component\Yaml\Exception\ParseException', $e, 'charsets other than UTF-8 are rejected.'); } } } /** * @expectedException \Symfony\Component\Yaml\Exception\ParseException */ public function testUnindentedCollectionException() { $yaml = <<<'EOF' collection: -item1 -item2 -item3 EOF; $this->parser->parse($yaml); } /** * @expectedException \Symfony\Component\Yaml\Exception\ParseException */ public function testShortcutKeyUnindentedCollectionException() { $yaml = <<<'EOF' collection: - key: foo foo: bar EOF; $this->parser->parse($yaml); } /** * @expectedException \Symfony\Component\Yaml\Exception\ParseException * @expectedExceptionMessageRegExp /^Multiple documents are not supported.+/ */ public function testMultipleDocumentsNotSupportedException() { Yaml::parse(<<<'EOL' # Ranking of 1998 home runs --- - Mark McGwire - Sammy Sosa - Ken Griffey # Team ranking --- - Chicago Cubs - St Louis Cardinals EOL ); } /** * @expectedException \Symfony\Component\Yaml\Exception\ParseException */ public function testSequenceInAMapping() { Yaml::parse(<<<'EOF' yaml: hash: me - array stuff EOF ); } public function testSequenceInMappingStartedBySingleDashLine() { $yaml = <<<'EOT' a: - b: - bar: baz - foo d: e EOT; $expected = array( 'a' => array( array( 'b' => array( array( 'bar' => 'baz', ), ), ), 'foo', ), 'd' => 'e', ); $this->assertSame($expected, $this->parser->parse($yaml)); } public function testSequenceFollowedByCommentEmbeddedInMapping() { $yaml = <<<'EOT' a: b: - c # comment d: e EOT; $expected = array( 'a' => array( 'b' => array('c'), 'd' => 'e', ), ); $this->assertSame($expected, $this->parser->parse($yaml)); } /** * @expectedException \Symfony\Component\Yaml\Exception\ParseException */ public function testMappingInASequence() { Yaml::parse(<<<'EOF' yaml: - array stuff hash: me EOF ); } /** * @expectedException \Symfony\Component\Yaml\Exception\ParseException * @expectedExceptionMessage missing colon */ public function testScalarInSequence() { Yaml::parse(<<<'EOF' foo: - bar "missing colon" foo: bar EOF ); } /** * > It is an error for two equal keys to appear in the same mapping node. * > In such a case the YAML processor may continue, ignoring the second * > `key: value` pair and issuing an appropriate warning. This strategy * > preserves a consistent information model for one-pass and random access * > applications. * * @see http://yaml.org/spec/1.2/spec.html#id2759572 * @see http://yaml.org/spec/1.1/#id932806 * @group legacy */ public function testMappingDuplicateKeyBlock() { $input = <<<'EOD' parent: child: first child: duplicate parent: child: duplicate child: duplicate EOD; $expected = array( 'parent' => array( 'child' => 'first', ), ); $this->assertSame($expected, Yaml::parse($input)); } /** * @group legacy */ public function testMappingDuplicateKeyFlow() { $input = <<<'EOD' parent: { child: first, child: duplicate } parent: { child: duplicate, child: duplicate } EOD; $expected = array( 'parent' => array( 'child' => 'first', ), ); $this->assertSame($expected, Yaml::parse($input)); } /** * @group legacy * @dataProvider getParseExceptionOnDuplicateData * @expectedDeprecation Duplicate key "%s" detected on line %d whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated %s. * throws \Symfony\Component\Yaml\Exception\ParseException in 4.0 */ public function testParseExceptionOnDuplicate($input, $duplicateKey, $lineNumber) { Yaml::parse($input); } public function getParseExceptionOnDuplicateData() { $tests = array(); $yaml = <<<EOD parent: { child: first, child: duplicate } EOD; $tests[] = array($yaml, 'child', 1); $yaml = <<<EOD parent: child: first, child: duplicate EOD; $tests[] = array($yaml, 'child', 3); $yaml = <<<EOD parent: { child: foo } parent: { child: bar } EOD; $tests[] = array($yaml, 'parent', 2); $yaml = <<<EOD parent: { child_mapping: { value: bar}, child_mapping: { value: bar} } EOD; $tests[] = array($yaml, 'child_mapping', 1); $yaml = <<<EOD parent: child_mapping: value: bar child_mapping: value: bar EOD; $tests[] = array($yaml, 'child_mapping', 4); $yaml = <<<EOD parent: { child_sequence: ['key1', 'key2', 'key3'], child_sequence: ['key1', 'key2', 'key3'] } EOD; $tests[] = array($yaml, 'child_sequence', 1); $yaml = <<<EOD parent: child_sequence: - key1 - key2 - key3 child_sequence: - key1 - key2 - key3 EOD; $tests[] = array($yaml, 'child_sequence', 6); return $tests; } public function testEmptyValue() { $input = <<<'EOF' hash: EOF; $this->assertEquals(array('hash' => null), Yaml::parse($input)); } public function testCommentAtTheRootIndent() { $this->assertEquals(array( 'services' => array( 'app.foo_service' => array( 'class' => 'Foo', ), 'app/bar_service' => array( 'class' => 'Bar', ), ), ), Yaml::parse(<<<'EOF' # comment 1 services: # comment 2 # comment 3 app.foo_service: class: Foo # comment 4 # comment 5 app/bar_service: class: Bar EOF )); } public function testStringBlockWithComments() { $this->assertEquals(array('content' => <<<'EOT' # comment 1 header # comment 2 <body> <h1>title</h1> </body> footer # comment3 EOT ), Yaml::parse(<<<'EOF' content: | # comment 1 header # comment 2 <body> <h1>title</h1> </body> footer # comment3 EOF )); } public function testFoldedStringBlockWithComments() { $this->assertEquals(array(array('content' => <<<'EOT' # comment 1 header # comment 2 <body> <h1>title</h1> </body> footer # comment3 EOT )), Yaml::parse(<<<'EOF' - content: | # comment 1 header # comment 2 <body> <h1>title</h1> </body> footer # comment3 EOF )); } public function testNestedFoldedStringBlockWithComments() { $this->assertEquals(array(array( 'title' => 'some title', 'content' => <<<'EOT' # comment 1 header # comment 2 <body> <h1>title</h1> </body> footer # comment3 EOT )), Yaml::parse(<<<'EOF' - title: some title content: | # comment 1 header # comment 2 <body> <h1>title</h1> </body> footer # comment3 EOF )); } public function testReferenceResolvingInInlineStrings() { $this->assertEquals(array( 'var' => 'var-value', 'scalar' => 'var-value', 'list' => array('var-value'), 'list_in_list' => array(array('var-value')), 'map_in_list' => array(array('key' => 'var-value')), 'embedded_mapping' => array(array('key' => 'var-value')), 'map' => array('key' => 'var-value'), 'list_in_map' => array('key' => array('var-value')), 'map_in_map' => array('foo' => array('bar' => 'var-value')), ), Yaml::parse(<<<'EOF' var: &var var-value scalar: *var list: [ *var ] list_in_list: [[ *var ]] map_in_list: [ { key: *var } ] embedded_mapping: [ key: *var ] map: { key: *var } list_in_map: { key: [*var] } map_in_map: { foo: { bar: *var } } EOF )); } public function testYamlDirective() { $yaml = <<<'EOF' %YAML 1.2 --- foo: 1 bar: 2 EOF; $this->assertEquals(array('foo' => 1, 'bar' => 2), $this->parser->parse($yaml)); } public function testFloatKeys() { $yaml = <<<'EOF' foo: 1.2: "bar" 1.3: "baz" EOF; $expected = array( 'foo' => array( '1.2' => 'bar', '1.3' => 'baz', ), ); $this->assertEquals($expected, $this->parser->parse($yaml)); } /** * @expectedException \Symfony\Component\Yaml\Exception\ParseException * @expectedExceptionMessage A colon cannot be used in an unquoted mapping value */ public function testColonInMappingValueException() { $yaml = <<<'EOF' foo: bar: baz EOF; $this->parser->parse($yaml); } public function testColonInMappingValueExceptionNotTriggeredByColonInComment() { $yaml = <<<'EOT' foo: bar: foobar # Note: a comment after a colon EOT; $this->assertSame(array('foo' => array('bar' => 'foobar')), $this->parser->parse($yaml)); } /** * @dataProvider getCommentLikeStringInScalarBlockData */ public function testCommentLikeStringsAreNotStrippedInBlockScalars($yaml, $expectedParserResult) { $this->assertSame($expectedParserResult, $this->parser->parse($yaml)); } public function getCommentLikeStringInScalarBlockData() { $tests = array(); $yaml = <<<'EOT' pages: - title: some title content: | # comment 1 header # comment 2 <body> <h1>title</h1> </body> footer # comment3 EOT; $expected = array( 'pages' => array( array( 'title' => 'some title', 'content' => <<<'EOT' # comment 1 header # comment 2 <body> <h1>title</h1> </body> footer # comment3 EOT , ), ), ); $tests[] = array($yaml, $expected); $yaml = <<<'EOT' test: | foo # bar baz collection: - one: | foo # bar baz - two: | foo # bar baz EOT; $expected = array( 'test' => <<<'EOT' foo # bar baz EOT , 'collection' => array( array( 'one' => <<<'EOT' foo # bar baz EOT , ), array( 'two' => <<<'EOT' foo # bar baz EOT , ), ), ); $tests[] = array($yaml, $expected); $yaml = <<<'EOT' foo: bar: scalar-block: > line1 line2> baz: # comment foobar: ~ EOT; $expected = array( 'foo' => array( 'bar' => array( 'scalar-block' => "line1 line2>\n", ), 'baz' => array( 'foobar' => null, ), ), ); $tests[] = array($yaml, $expected); $yaml = <<<'EOT' a: b: hello # c: | # first row # second row d: hello EOT; $expected = array( 'a' => array( 'b' => 'hello', 'd' => 'hello', ), ); $tests[] = array($yaml, $expected); return $tests; } public function testBlankLinesAreParsedAsNewLinesInFoldedBlocks() { $yaml = <<<'EOT' test: > <h2>A heading</h2> <ul> <li>a list</li> <li>may be a good example</li> </ul> EOT; $this->assertSame( array( 'test' => <<<'EOT' <h2>A heading</h2> <ul> <li>a list</li> <li>may be a good example</li> </ul> EOT , ), $this->parser->parse($yaml) ); } public function testAdditionallyIndentedLinesAreParsedAsNewLinesInFoldedBlocks() { $yaml = <<<'EOT' test: > <h2>A heading</h2> <ul> <li>a list</li> <li>may be a good example</li> </ul> EOT; $this->assertSame( array( 'test' => <<<'EOT' <h2>A heading</h2> <ul> <li>a list</li> <li>may be a good example</li> </ul> EOT , ), $this->parser->parse($yaml) ); } /** * @dataProvider getBinaryData */ public function testParseBinaryData($data) { $this->assertSame(array('data' => 'Hello world'), $this->parser->parse($data)); } public function getBinaryData() { return array( 'enclosed with double quotes' => array('data: !!binary "SGVsbG8gd29ybGQ="'), 'enclosed with single quotes' => array("data: !!binary 'SGVsbG8gd29ybGQ='"), 'containing spaces' => array('data: !!binary "SGVs bG8gd 29ybGQ="'), 'in block scalar' => array( <<<'EOT' data: !!binary | SGVsbG8gd29ybGQ= EOT ), 'containing spaces in block scalar' => array( <<<'EOT' data: !!binary | SGVs bG8gd 29ybGQ= EOT ), ); } /** * @dataProvider getInvalidBinaryData * @expectedException \Symfony\Component\Yaml\Exception\ParseException */ public function testParseInvalidBinaryData($data, $expectedMessage) { if (method_exists($this, 'expectException')) { $this->expectExceptionMessageRegExp($expectedMessage); } else { $this->setExpectedExceptionRegExp(ParseException::class, $expectedMessage); } $this->parser->parse($data); } public function getInvalidBinaryData() { return array( 'length not a multiple of four' => array('data: !!binary "SGVsbG8d29ybGQ="', '/The normalized base64 encoded data \(data without whitespace characters\) length must be a multiple of four \(\d+ bytes given\)/'), 'invalid characters' => array('!!binary "SGVsbG8#d29ybGQ="', '/The base64 encoded data \(.*\) contains invalid characters/'), 'too many equals characters' => array('data: !!binary "SGVsbG8gd29yb==="', '/The base64 encoded data \(.*\) contains invalid characters/'), 'misplaced equals character' => array('data: !!binary "SGVsbG8gd29ybG=Q"', '/The base64 encoded data \(.*\) contains invalid characters/'), 'length not a multiple of four in block scalar' => array( <<<'EOT' data: !!binary | SGVsbG8d29ybGQ= EOT , '/The normalized base64 encoded data \(data without whitespace characters\) length must be a multiple of four \(\d+ bytes given\)/', ), 'invalid characters in block scalar' => array( <<<'EOT' data: !!binary | SGVsbG8#d29ybGQ= EOT , '/The base64 encoded data \(.*\) contains invalid characters/', ), 'too many equals characters in block scalar' => array( <<<'EOT' data: !!binary | SGVsbG8gd29yb=== EOT , '/The base64 encoded data \(.*\) contains invalid characters/', ), 'misplaced equals character in block scalar' => array( <<<'EOT' data: !!binary | SGVsbG8gd29ybG=Q EOT , '/The base64 encoded data \(.*\) contains invalid characters/', ), ); } public function testParseDateAsMappingValue() { $yaml = <<<'EOT' date: 2002-12-14 EOT; $expectedDate = new \DateTime(); $expectedDate->setTimeZone(new \DateTimeZone('UTC')); $expectedDate->setDate(2002, 12, 14); $expectedDate->setTime(0, 0, 0); $this->assertEquals(array('date' => $expectedDate), $this->parser->parse($yaml, Yaml::PARSE_DATETIME)); } /** * @param $lineNumber * @param $yaml * @dataProvider parserThrowsExceptionWithCorrectLineNumberProvider */ public function testParserThrowsExceptionWithCorrectLineNumber($lineNumber, $yaml) { if (method_exists($this, 'expectException')) { $this->expectException('\Symfony\Component\Yaml\Exception\ParseException'); $this->expectExceptionMessage(sprintf('Unexpected characters near "," at line %d (near "bar: "123",").', $lineNumber)); } else { $this->setExpectedException('\Symfony\Component\Yaml\Exception\ParseException', sprintf('Unexpected characters near "," at line %d (near "bar: "123",").', $lineNumber)); } $this->parser->parse($yaml); } public function parserThrowsExceptionWithCorrectLineNumberProvider() { return array( array( 4, <<<'YAML' foo: - # bar bar: "123", YAML ), array( 5, <<<'YAML' foo: - # bar # bar bar: "123", YAML ), array( 8, <<<'YAML' foo: - # foobar baz: 123 bar: - # bar bar: "123", YAML ), array( 10, <<<'YAML' foo: - # foobar # foobar baz: 123 bar: - # bar # bar bar: "123", YAML ), ); } public function testParseMultiLineQuotedString() { $yaml = <<<EOT foo: "bar baz foobar foo" bar: baz EOT; $this->assertSame(array('foo' => 'bar baz foobar foo', 'bar' => 'baz'), $this->parser->parse($yaml)); } public function testParseMultiLineUnquotedString() { $yaml = <<<EOT foo: bar baz foobar foo bar: baz EOT; $this->assertSame(array('foo' => 'bar baz foobar foo', 'bar' => 'baz'), $this->parser->parse($yaml)); } } class B { public $b = 'foo'; } symfony/yaml/Tests/Fixtures/sfCompact.yml 0000604 00000005525 15247160545 0014603 0 ustar 00 --- %YAML:1.0 test: Compact notation brief: | Compact notation for sets of mappings with single element yaml: | --- # products purchased - item : Super Hoop - item : Basketball quantity: 1 - item: name: Big Shoes nick: Biggies quantity: 1 php: | array ( array ( 'item' => 'Super Hoop', ), array ( 'item' => 'Basketball', 'quantity' => 1, ), array ( 'item' => array( 'name' => 'Big Shoes', 'nick' => 'Biggies' ), 'quantity' => 1 ) ) --- test: Compact notation combined with inline notation brief: | Combinations of compact and inline notation are allowed yaml: | --- items: - { item: Super Hoop, quantity: 1 } - [ Basketball, Big Shoes ] php: | array ( 'items' => array ( array ( 'item' => 'Super Hoop', 'quantity' => 1, ), array ( 'Basketball', 'Big Shoes' ) ) ) --- %YAML:1.0 test: Compact notation brief: | Compact notation for sets of mappings with single element yaml: | --- # products purchased - item : Super Hoop - item : Basketball quantity: 1 - item: name: Big Shoes nick: Biggies quantity: 1 php: | array ( array ( 'item' => 'Super Hoop', ), array ( 'item' => 'Basketball', 'quantity' => 1, ), array ( 'item' => array( 'name' => 'Big Shoes', 'nick' => 'Biggies' ), 'quantity' => 1 ) ) --- test: Compact notation combined with inline notation brief: | Combinations of compact and inline notation are allowed yaml: | --- items: - { item: Super Hoop, quantity: 1 } - [ Basketball, Big Shoes ] php: | array ( 'items' => array ( array ( 'item' => 'Super Hoop', 'quantity' => 1, ), array ( 'Basketball', 'Big Shoes' ) ) ) --- %YAML:1.0 test: Compact notation brief: | Compact notation for sets of mappings with single element yaml: | --- # products purchased - item : Super Hoop - item : Basketball quantity: 1 - item: name: Big Shoes nick: Biggies quantity: 1 php: | array ( array ( 'item' => 'Super Hoop', ), array ( 'item' => 'Basketball', 'quantity' => 1, ), array ( 'item' => array( 'name' => 'Big Shoes', 'nick' => 'Biggies' ), 'quantity' => 1 ) ) --- test: Compact notation combined with inline notation brief: | Combinations of compact and inline notation are allowed yaml: | --- items: - { item: Super Hoop, quantity: 1 } - [ Basketball, Big Shoes ] php: | array ( 'items' => array ( array ( 'item' => 'Super Hoop', 'quantity' => 1, ), array ( 'Basketball', 'Big Shoes' ) ) ) symfony/yaml/Tests/Fixtures/YtsErrorTests.yml 0000604 00000001161 15247160545 0015470 0 ustar 00 --- test: Missing value for hash item todo: true brief: | Third item in this hash doesn't have a value yaml: | okay: value also okay: ~ causes error because no value specified last key: value okay here too python-error: causes error because no value specified --- test: Not indenting enough brief: | There was a bug in PyYaml where it was off by one in the indentation check. It was allowing the YAML below. # This is actually valid YAML now. Someone should tell showell. yaml: | foo: firstline: 1 secondline: 2 php: | array('foo' => null, 'firstline' => 1, 'secondline' => 2) symfony/yaml/Tests/Fixtures/index.yml 0000604 00000000470 15247160545 0013765 0 ustar 00 - escapedCharacters - sfComments - sfCompact - sfTests - sfObjects - sfMergeKey - sfQuotes - YtsAnchorAlias - YtsBasicTests - YtsBlockMapping - YtsDocumentSeparator - YtsErrorTests - YtsFlowCollections - YtsFoldedScalars - YtsNullsAndEmpties - YtsSpecificationExamples - YtsTypeTransfers - unindentedCollections symfony/yaml/Tests/Fixtures/YtsBlockMapping.yml 0000604 00000001627 15247160545 0015731 0 ustar 00 --- test: One Element Mapping brief: | A mapping with one key/value pair yaml: | foo: bar php: | array('foo' => 'bar') --- test: Multi Element Mapping brief: | More than one key/value pair yaml: | red: baron white: walls blue: berries php: | array( 'red' => 'baron', 'white' => 'walls', 'blue' => 'berries', ) --- test: Values aligned brief: | Often times human editors of documents will align the values even though YAML emitters generally don't. yaml: | red: baron white: walls blue: berries php: | array( 'red' => 'baron', 'white' => 'walls', 'blue' => 'berries', ) --- test: Colons aligned brief: | Spaces can come before the ': ' key/value separator. yaml: | red : baron white : walls blue : berries php: | array( 'red' => 'baron', 'white' => 'walls', 'blue' => 'berries', ) symfony/yaml/Tests/Fixtures/YtsFoldedScalars.yml 0000604 00000007572 15247160545 0016076 0 ustar 00 --- %YAML:1.0 test: Single ending newline brief: > A pipe character, followed by an indented block of text is treated as a literal block, in which newlines are preserved throughout the block, including the final newline. yaml: | --- this: | Foo Bar php: | array('this' => "Foo\nBar\n") --- test: The '+' indicator brief: > The '+' indicator says to keep newlines at the end of text blocks. yaml: | normal: | extra new lines not kept preserving: |+ extra new lines are kept dummy: value php: | array( 'normal' => "extra new lines not kept\n", 'preserving' => "extra new lines are kept\n\n\n", 'dummy' => 'value' ) --- test: Three trailing newlines in literals brief: > To give you more control over how space is preserved in text blocks, YAML has the keep '+' and chomp '-' indicators. The keep indicator will preserve all ending newlines, while the chomp indicator will strip all ending newlines. yaml: | clipped: | This has one newline. same as "clipped" above: "This has one newline.\n" stripped: |- This has no newline. same as "stripped" above: "This has no newline." kept: |+ This has four newlines. same as "kept" above: "This has four newlines.\n\n\n\n" php: | array( 'clipped' => "This has one newline.\n", 'same as "clipped" above' => "This has one newline.\n", 'stripped' => 'This has no newline.', 'same as "stripped" above' => 'This has no newline.', 'kept' => "This has four newlines.\n\n\n\n", 'same as "kept" above' => "This has four newlines.\n\n\n\n" ) --- test: Extra trailing newlines with spaces todo: true brief: > Normally, only a single newline is kept from the end of a literal block, unless the keep '+' character is used in combination with the pipe. The following example will preserve all ending whitespace since the last line of both literal blocks contains spaces which extend past the indentation level. yaml: | --- this: | Foo kept: |+ Foo php: | array('this' => "Foo\n\n \n", 'kept' => "Foo\n\n \n" ) --- test: Folded Block in a Sequence brief: > A greater-then character, followed by an indented block of text is treated as a folded block, in which lines of text separated by a single newline are concatenated as a single line. yaml: | --- - apple - banana - > can't you see the beauty of yaml? hmm - dog php: | array( 'apple', 'banana', "can't you see the beauty of yaml? hmm\n", 'dog' ) --- test: Folded Block as a Mapping Value brief: > Both literal and folded blocks can be used in collections, as values in a sequence or a mapping. yaml: | --- quote: > Mark McGwire's year was crippled by a knee injury. source: espn php: | array( 'quote' => "Mark McGwire's year was crippled by a knee injury.\n", 'source' => 'espn' ) --- test: Three trailing newlines in folded blocks brief: > The keep and chomp indicators can also be applied to folded blocks. yaml: | clipped: > This has one newline. same as "clipped" above: "This has one newline.\n" stripped: >- This has no newline. same as "stripped" above: "This has no newline." kept: >+ This has four newlines. same as "kept" above: "This has four newlines.\n\n\n\n" php: | array( 'clipped' => "This has one newline.\n", 'same as "clipped" above' => "This has one newline.\n", 'stripped' => 'This has no newline.', 'same as "stripped" above' => 'This has no newline.', 'kept' => "This has four newlines.\n\n\n\n", 'same as "kept" above' => "This has four newlines.\n\n\n\n" ) symfony/yaml/Tests/Fixtures/sfQuotes.yml 0000604 00000001347 15247160545 0014473 0 ustar 00 --- %YAML:1.0 test: Some characters at the beginning of a string must be escaped brief: > Some characters at the beginning of a string must be escaped yaml: | foo: '| bar' php: | array('foo' => '| bar') --- test: A key can be a quoted string brief: > A key can be a quoted string yaml: | "foo1": bar 'foo2': bar "foo \" bar": bar 'foo '' bar': bar 'foo3: ': bar "foo4: ": bar foo5: { "foo \" bar: ": bar, 'foo '' bar: ': bar } php: | array( 'foo1' => 'bar', 'foo2' => 'bar', 'foo " bar' => 'bar', 'foo \' bar' => 'bar', 'foo3: ' => 'bar', 'foo4: ' => 'bar', 'foo5' => array( 'foo " bar: ' => 'bar', 'foo \' bar: ' => 'bar', ), ) symfony/yaml/Tests/Fixtures/unindentedCollections.yml 0000604 00000003430 15247160545 0017211 0 ustar 00 --- %YAML:1.0 test: Unindented collection brief: > Unindented collection yaml: | collection: - item1 - item2 - item3 php: | array('collection' => array('item1', 'item2', 'item3')) --- test: Nested unindented collection (two levels) brief: > Nested unindented collection yaml: | collection: key: - a - b - c php: | array('collection' => array('key' => array('a', 'b', 'c'))) --- test: Nested unindented collection (three levels) brief: > Nested unindented collection yaml: | collection: key: subkey: - one - two - three php: | array('collection' => array('key' => array('subkey' => array('one', 'two', 'three')))) --- test: Key/value after unindented collection (1) brief: > Key/value after unindented collection (1) yaml: | collection: key: - a - b - c foo: bar php: | array('collection' => array('key' => array('a', 'b', 'c')), 'foo' => 'bar') --- test: Key/value after unindented collection (at the same level) brief: > Key/value after unindented collection yaml: | collection: key: - a - b - c foo: bar php: | array('collection' => array('key' => array('a', 'b', 'c'), 'foo' => 'bar')) --- test: Shortcut Key after unindented collection brief: > Key/value after unindented collection yaml: | collection: - key: foo foo: bar php: | array('collection' => array(array('key' => 'foo', 'foo' => 'bar'))) --- test: Shortcut Key after unindented collection with custom spaces brief: > Key/value after unindented collection yaml: | collection: - key: foo foo: bar php: | array('collection' => array(array('key' => 'foo', 'foo' => 'bar'))) symfony/yaml/Tests/Fixtures/YtsBasicTests.yml 0000604 00000010463 15247160545 0015425 0 ustar 00 --- %YAML:1.0 test: Simple Sequence brief: | You can specify a list in YAML by placing each member of the list on a new line with an opening dash. These lists are called sequences. yaml: | - apple - banana - carrot php: | array('apple', 'banana', 'carrot') --- test: Sequence With Item Being Null In The Middle brief: | You can specify a list in YAML by placing each member of the list on a new line with an opening dash. These lists are called sequences. yaml: | - apple - - carrot php: | array('apple', null, 'carrot') --- test: Sequence With Last Item Being Null brief: | You can specify a list in YAML by placing each member of the list on a new line with an opening dash. These lists are called sequences. yaml: | - apple - banana - php: | array('apple', 'banana', null) --- test: Nested Sequences brief: | You can include a sequence within another sequence by giving the sequence an empty dash, followed by an indented list. yaml: | - - foo - bar - baz php: | array(array('foo', 'bar', 'baz')) --- test: Mixed Sequences brief: | Sequences can contain any YAML data, including strings and other sequences. yaml: | - apple - - foo - bar - x123 - banana - carrot php: | array('apple', array('foo', 'bar', 'x123'), 'banana', 'carrot') --- test: Deeply Nested Sequences brief: | Sequences can be nested even deeper, with each level of indentation representing a level of depth. yaml: | - - - uno - dos php: | array(array(array('uno', 'dos'))) --- test: Simple Mapping brief: | You can add a keyed list (also known as a dictionary or hash) to your document by placing each member of the list on a new line, with a colon separating the key from its value. In YAML, this type of list is called a mapping. yaml: | foo: whatever bar: stuff php: | array('foo' => 'whatever', 'bar' => 'stuff') --- test: Sequence in a Mapping brief: | A value in a mapping can be a sequence. yaml: | foo: whatever bar: - uno - dos php: | array('foo' => 'whatever', 'bar' => array('uno', 'dos')) --- test: Nested Mappings brief: | A value in a mapping can be another mapping. yaml: | foo: whatever bar: fruit: apple name: steve sport: baseball php: | array( 'foo' => 'whatever', 'bar' => array( 'fruit' => 'apple', 'name' => 'steve', 'sport' => 'baseball' ) ) --- test: Mixed Mapping brief: | A mapping can contain any assortment of mappings and sequences as values. yaml: | foo: whatever bar: - fruit: apple name: steve sport: baseball - more - python: rocks perl: papers ruby: scissorses php: | array( 'foo' => 'whatever', 'bar' => array( array( 'fruit' => 'apple', 'name' => 'steve', 'sport' => 'baseball' ), 'more', array( 'python' => 'rocks', 'perl' => 'papers', 'ruby' => 'scissorses' ) ) ) --- test: Mapping-in-Sequence Shortcut todo: true brief: | If you are adding a mapping to a sequence, you can place the mapping on the same line as the dash as a shortcut. yaml: | - work on YAML.py: - work on Store php: | array(array('work on YAML.py' => array('work on Store'))) --- test: Sequence-in-Mapping Shortcut todo: true brief: | The dash in a sequence counts as indentation, so you can add a sequence inside of a mapping without needing spaces as indentation. yaml: | allow: - 'localhost' - '%.sourceforge.net' - '%.freepan.org' php: | array('allow' => array('localhost', '%.sourceforge.net', '%.freepan.org')) --- todo: true test: Merge key brief: | A merge key ('<<') can be used in a mapping to insert other mappings. If the value associated with the merge key is a mapping, each of its key/value pairs is inserted into the current mapping. yaml: | mapping: name: Joe job: Accountant <<: age: 38 php: | array( 'mapping' => array( 'name' => 'Joe', 'job' => 'Accountant', 'age' => 38 ) ) symfony/yaml/Tests/Fixtures/sfComments.yml 0000604 00000003226 15247160545 0014776 0 ustar 00 --- %YAML:1.0 test: Comments at the end of a line brief: > Comments at the end of a line yaml: | ex1: "foo # bar" ex2: "foo # bar" # comment ex3: 'foo # bar' # comment ex4: foo # comment ex5: foo # comment with tab before ex6: foo#foo # comment here ex7: foo # ignore me # and me php: | array('ex1' => 'foo # bar', 'ex2' => 'foo # bar', 'ex3' => 'foo # bar', 'ex4' => 'foo', 'ex5' => 'foo', 'ex6' => 'foo#foo', 'ex7' => 'foo') --- test: Comments in the middle brief: > Comments in the middle yaml: | foo: # some comment # some comment bar: foo # some comment # some comment php: | array('foo' => array('bar' => 'foo')) --- test: Comments on a hash line brief: > Comments on a hash line yaml: | foo: # a comment foo: bar # a comment php: | array('foo' => array('foo' => 'bar')) --- test: 'Value starting with a #' brief: > 'Value starting with a #' yaml: | foo: '#bar' php: | array('foo' => '#bar') --- test: Document starting with a comment and a separator brief: > Commenting before document start is allowed yaml: | # document comment --- foo: bar # a comment php: | array('foo' => 'bar') --- test: Comment containing a colon on a hash line brief: > Comment containing a colon on a scalar line yaml: 'foo # comment: this is also part of the comment' php: | 'foo' --- test: 'Hash key containing a #' brief: > 'Hash key containing a #' yaml: 'foo#bar: baz' php: | array('foo#bar' => 'baz') --- test: 'Hash key ending with a space and a #' brief: > 'Hash key ending with a space and a #' yaml: | 'foo #': baz php: | array('foo #' => 'baz') symfony/yaml/Tests/Fixtures/YtsDocumentSeparator.yml 0000604 00000002773 15247160545 0017025 0 ustar 00 --- %YAML:1.0 test: Trailing Document Separator todo: true brief: > You can separate YAML documents with a string of three dashes. yaml: | - foo: 1 bar: 2 --- more: stuff python: | [ [ { 'foo': 1, 'bar': 2 } ], { 'more': 'stuff' } ] ruby: | [ { 'foo' => 1, 'bar' => 2 } ] --- test: Leading Document Separator todo: true brief: > You can explicitly give an opening document separator to your YAML stream. yaml: | --- - foo: 1 bar: 2 --- more: stuff python: | [ [ {'foo': 1, 'bar': 2}], {'more': 'stuff'} ] ruby: | [ { 'foo' => 1, 'bar' => 2 } ] --- test: YAML Header todo: true brief: > The opening separator can contain directives to the YAML parser, such as the version number. yaml: | --- %YAML:1.0 foo: 1 bar: 2 php: | array('foo' => 1, 'bar' => 2) documents: 1 --- test: Red Herring Document Separator brief: > Separators included in blocks or strings are treated as blocks or strings, as the document separator should have no indentation preceding it. yaml: | foo: | --- php: | array('foo' => "---\n") --- test: Multiple Document Separators in Block brief: > This technique allows you to embed other YAML documents within literal blocks. yaml: | foo: | --- foo: bar --- yo: baz bar: | fooness php: | array( 'foo' => "---\nfoo: bar\n---\nyo: baz\n", 'bar' => "fooness\n" ) symfony/yaml/Tests/Fixtures/sfTests.yml 0000604 00000004671 15247160545 0014320 0 ustar 00 --- %YAML:1.0 test: Multiple quoted string on one line brief: > Multiple quoted string on one line yaml: | stripped_title: { name: "foo bar", help: "bar foo" } php: | array('stripped_title' => array('name' => 'foo bar', 'help' => 'bar foo')) --- test: Empty sequence yaml: | foo: [ ] php: | array('foo' => array()) --- test: Empty value yaml: | foo: php: | array('foo' => null) --- test: Inline string parsing brief: > Inline string parsing yaml: | test: ['complex: string', 'another [string]'] php: | array('test' => array('complex: string', 'another [string]')) --- test: Boolean brief: > Boolean yaml: | - false - true - null - ~ - 'false' - 'true' - 'null' - '~' php: | array( false, true, null, null, 'false', 'true', 'null', '~', ) --- test: Empty lines in literal blocks brief: > Empty lines in literal blocks yaml: | foo: bar: | foo bar php: | array('foo' => array('bar' => "foo\n\n\n \nbar\n")) --- test: Empty lines in folded blocks brief: > Empty lines in folded blocks yaml: | foo: bar: > foo bar php: | array('foo' => array('bar' => "\nfoo\n\nbar\n")) --- test: IP addresses brief: > IP addresses yaml: | foo: 10.0.0.2 php: | array('foo' => '10.0.0.2') --- test: A sequence with an embedded mapping brief: > A sequence with an embedded mapping yaml: | - foo - bar: { bar: foo } php: | array('foo', array('bar' => array('bar' => 'foo'))) --- test: A sequence with an unordered array brief: > A sequence with an unordered array yaml: | 1: foo 0: bar php: | array(1 => 'foo', 0 => 'bar') --- test: Octal brief: as in spec example 2.19, octal value is converted yaml: | foo: 0123 php: | array('foo' => 83) --- test: Octal strings brief: Octal notation in a string must remain a string yaml: | foo: "0123" php: | array('foo' => '0123') --- test: Octal strings brief: Octal notation in a string must remain a string yaml: | foo: '0123' php: | array('foo' => '0123') --- test: Octal strings brief: Octal notation in a string must remain a string yaml: | foo: | 0123 php: | array('foo' => "0123\n") --- test: Document as a simple hash brief: Document as a simple hash yaml: | { foo: bar } php: | array('foo' => 'bar') --- test: Document as a simple array brief: Document as a simple array yaml: | [ foo, bar ] php: | array('foo', 'bar') symfony/yaml/Tests/Fixtures/YtsAnchorAlias.yml 0000604 00000001533 15247160545 0015543 0 ustar 00 --- %YAML:1.0 test: Simple Alias Example brief: > If you need to refer to the same item of data twice, you can give that item an alias. The alias is a plain string, starting with an ampersand. The item may then be referred to by the alias throughout your document by using an asterisk before the name of the alias. This is called an anchor. yaml: | - &showell Steve - Clark - Brian - Oren - *showell php: | array('Steve', 'Clark', 'Brian', 'Oren', 'Steve') --- test: Alias of a Mapping brief: > An alias can be used on any item of data, including sequences, mappings, and other complex data types. yaml: | - &hello Meat: pork Starch: potato - banana - *hello php: | array(array('Meat'=>'pork', 'Starch'=>'potato'), 'banana', array('Meat'=>'pork', 'Starch'=>'potato')) symfony/yaml/Tests/Fixtures/sfObjects.yml 0000604 00000000434 15247160545 0014600 0 ustar 00 --- %YAML:1.0 test: Objects brief: > Comments at the end of a line yaml: | ex1: "foo # bar" ex2: "foo # bar" # comment ex3: 'foo # bar' # comment ex4: foo # comment php: | array('ex1' => 'foo # bar', 'ex2' => 'foo # bar', 'ex3' => 'foo # bar', 'ex4' => 'foo') symfony/yaml/Tests/Fixtures/embededPhp.yml 0000604 00000000037 15247160545 0014712 0 ustar 00 value: <?php echo 1 + 2 + 3 ?> symfony/yaml/Tests/Fixtures/YtsNullsAndEmpties.yml 0000604 00000001253 15247160545 0016425 0 ustar 00 --- %YAML:1.0 test: Empty Sequence brief: > You can represent the empty sequence with an empty inline sequence. yaml: | empty: [] php: | array('empty' => array()) --- test: Empty Mapping brief: > You can represent the empty mapping with an empty inline mapping. yaml: | empty: {} php: | array('empty' => array()) --- test: Empty Sequence as Entire Document yaml: | [] php: | array() --- test: Empty Mapping as Entire Document yaml: | {} php: | array() --- test: Null as Document yaml: | ~ php: | null --- test: Empty String brief: > You can represent an empty string with a pair of quotes. yaml: | '' php: | '' symfony/yaml/Tests/Fixtures/sfMergeKey.yml 0000604 00000003341 15247160545 0014717 0 ustar 00 --- %YAML:1.0 test: Simple In Place Substitution brief: > If you want to reuse an entire alias, only overwriting what is different you can use a << in place substitution. This is not part of the official YAML spec, but a widely implemented extension. See the following URL for details: http://yaml.org/type/merge.html yaml: | foo: &foo a: Steve b: Clark c: Brian e: notnull bar: a: before d: other e: ~ <<: *foo b: new x: Oren c: foo: bar bar: foo foo2: &foo2 a: Ballmer ding: &dong [ fi, fei, fo, fam] check: <<: - *foo - *dong isit: tested head: <<: [ *foo , *dong , *foo2 ] taz: &taz a: Steve w: p: 1234 nested: <<: *taz d: Doug w: &nestedref p: 12345 z: <<: *nestedref php: | array( 'foo' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'e' => 'notnull'), 'bar' => array('a' => 'before', 'd' => 'other', 'e' => null, 'b' => 'new', 'c' => array('foo' => 'bar', 'bar' => 'foo'), 'x' => 'Oren'), 'foo2' => array('a' => 'Ballmer'), 'ding' => array('fi', 'fei', 'fo', 'fam'), 'check' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'e' => 'notnull', 'fi', 'fei', 'fo', 'fam', 'isit' => 'tested'), 'head' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'e' => 'notnull', 'fi', 'fei', 'fo', 'fam'), 'taz' => array('a' => 'Steve', 'w' => array('p' => 1234)), 'nested' => array('a' => 'Steve', 'w' => array('p' => 12345), 'd' => 'Doug', 'z' => array('p' => 12345)) ) symfony/yaml/Tests/Fixtures/escapedCharacters.yml 0000604 00000004274 15247160545 0016270 0 ustar 00 test: outside double quotes yaml: | \0 \ \a \b \n php: | "\\0 \\ \\a \\b \\n" --- test: null yaml: | "\0" php: | "\x00" --- test: bell yaml: | "\a" php: | "\x07" --- test: backspace yaml: | "\b" php: | "\x08" --- test: horizontal tab (1) yaml: | "\t" php: | "\x09" --- test: horizontal tab (2) yaml: | "\ " php: | "\x09" --- test: line feed yaml: | "\n" php: | "\x0a" --- test: vertical tab yaml: | "\v" php: | "\x0b" --- test: form feed yaml: | "\f" php: | "\x0c" --- test: carriage return yaml: | "\r" php: | "\x0d" --- test: escape yaml: | "\e" php: | "\x1b" --- test: space yaml: | "\ " php: | "\x20" --- test: slash yaml: | "\/" php: | "\x2f" --- test: backslash yaml: | "\\" php: | "\\" --- test: Unicode next line yaml: | "\N" php: | "\xc2\x85" --- test: Unicode non-breaking space yaml: | "\_" php: | "\xc2\xa0" --- test: Unicode line separator yaml: | "\L" php: | "\xe2\x80\xa8" --- test: Unicode paragraph separator yaml: | "\P" php: | "\xe2\x80\xa9" --- test: Escaped 8-bit Unicode yaml: | "\x42" php: | "B" --- test: Escaped 16-bit Unicode yaml: | "\u20ac" php: | "\xe2\x82\xac" --- test: Escaped 32-bit Unicode yaml: | "\U00000043" php: | "C" --- test: Example 5.13 Escaped Characters note: | Currently throws an error parsing first line. Maybe Symfony Yaml doesn't support continuation of string across multiple lines? Keeping test here but disabled. todo: true yaml: | "Fun with \\ \" \a \b \e \f \ \n \r \t \v \0 \ \ \_ \N \L \P \ \x41 \u0041 \U00000041" php: | "Fun with \x5C\n\x22 \x07 \x08 \x1B \x0C\n\x0A \x0D \x09 \x0B \x00\n\x20 \xA0 \x85 \xe2\x80\xa8 \xe2\x80\xa9\nA A A" --- test: Double quotes with a line feed yaml: | { double: "some value\n \"some quoted string\" and 'some single quotes one'" } php: | array( 'double' => "some value\n \"some quoted string\" and 'some single quotes one'" ) --- test: Backslashes yaml: | { single: 'foo\Var', no-quotes: foo\Var, double: "foo\\Var" } php: | array( 'single' => 'foo\Var', 'no-quotes' => 'foo\Var', 'double' => 'foo\Var' ) symfony/yaml/Tests/Fixtures/YtsSpecificationExamples.yml 0000604 00000121637 15247160545 0017646 0 ustar 00 --- %YAML:1.0 test: Sequence of scalars spec: 2.1 yaml: | - Mark McGwire - Sammy Sosa - Ken Griffey php: | array('Mark McGwire', 'Sammy Sosa', 'Ken Griffey') --- test: Mapping of scalars to scalars spec: 2.2 yaml: | hr: 65 avg: 0.278 rbi: 147 php: | array('hr' => 65, 'avg' => 0.278, 'rbi' => 147) --- test: Mapping of scalars to sequences spec: 2.3 yaml: | american: - Boston Red Sox - Detroit Tigers - New York Yankees national: - New York Mets - Chicago Cubs - Atlanta Braves php: | array('american' => array( 'Boston Red Sox', 'Detroit Tigers', 'New York Yankees' ), 'national' => array( 'New York Mets', 'Chicago Cubs', 'Atlanta Braves' ) ) --- test: Sequence of mappings spec: 2.4 yaml: | - name: Mark McGwire hr: 65 avg: 0.278 - name: Sammy Sosa hr: 63 avg: 0.288 php: | array( array('name' => 'Mark McGwire', 'hr' => 65, 'avg' => 0.278), array('name' => 'Sammy Sosa', 'hr' => 63, 'avg' => 0.288) ) --- test: Legacy A5 todo: true spec: legacy_A5 yaml: | ? - New York Yankees - Atlanta Braves : - 2001-07-02 - 2001-08-12 - 2001-08-14 ? - Detroit Tigers - Chicago Cubs : - 2001-07-23 perl-busted: > YAML.pm will be able to emulate this behavior soon. In this regard it may be somewhat more correct than Python's native behaviour which can only use tuples as mapping keys. PyYAML will also need to figure out some clever way to roundtrip structured keys. python: | [ { ('New York Yankees', 'Atlanta Braves'): [yaml.timestamp('2001-07-02'), yaml.timestamp('2001-08-12'), yaml.timestamp('2001-08-14')], ('Detroit Tigers', 'Chicago Cubs'): [yaml.timestamp('2001-07-23')] } ] ruby: | { [ 'New York Yankees', 'Atlanta Braves' ] => [ Date.new( 2001, 7, 2 ), Date.new( 2001, 8, 12 ), Date.new( 2001, 8, 14 ) ], [ 'Detroit Tigers', 'Chicago Cubs' ] => [ Date.new( 2001, 7, 23 ) ] } syck: | struct test_node seq1[] = { { T_STR, 0, "New York Yankees" }, { T_STR, 0, "Atlanta Braves" }, end_node }; struct test_node seq2[] = { { T_STR, 0, "2001-07-02" }, { T_STR, 0, "2001-08-12" }, { T_STR, 0, "2001-08-14" }, end_node }; struct test_node seq3[] = { { T_STR, 0, "Detroit Tigers" }, { T_STR, 0, "Chicago Cubs" }, end_node }; struct test_node seq4[] = { { T_STR, 0, "2001-07-23" }, end_node }; struct test_node map[] = { { T_SEQ, 0, 0, seq1 }, { T_SEQ, 0, 0, seq2 }, { T_SEQ, 0, 0, seq3 }, { T_SEQ, 0, 0, seq4 }, end_node }; struct test_node stream[] = { { T_MAP, 0, 0, map }, end_node }; --- test: Sequence of sequences spec: 2.5 yaml: | - [ name , hr , avg ] - [ Mark McGwire , 65 , 0.278 ] - [ Sammy Sosa , 63 , 0.288 ] php: | array( array( 'name', 'hr', 'avg' ), array( 'Mark McGwire', 65, 0.278 ), array( 'Sammy Sosa', 63, 0.288 ) ) --- test: Mapping of mappings todo: true spec: 2.6 yaml: | Mark McGwire: {hr: 65, avg: 0.278} Sammy Sosa: { hr: 63, avg: 0.288 } php: | array( 'Mark McGwire' => array( 'hr' => 65, 'avg' => 0.278 ), 'Sammy Sosa' => array( 'hr' => 63, 'avg' => 0.288 ) ) --- test: Two documents in a stream each with a leading comment todo: true spec: 2.7 yaml: | # Ranking of 1998 home runs --- - Mark McGwire - Sammy Sosa - Ken Griffey # Team ranking --- - Chicago Cubs - St Louis Cardinals ruby: | y = YAML::Stream.new y.add( [ 'Mark McGwire', 'Sammy Sosa', 'Ken Griffey' ] ) y.add( [ 'Chicago Cubs', 'St Louis Cardinals' ] ) documents: 2 --- test: Play by play feed from a game todo: true spec: 2.8 yaml: | --- time: 20:03:20 player: Sammy Sosa action: strike (miss) ... --- time: 20:03:47 player: Sammy Sosa action: grand slam ... perl: | [ 'Mark McGwire', 'Sammy Sosa', 'Ken Griffey' ] documents: 2 --- test: Single document with two comments spec: 2.9 yaml: | hr: # 1998 hr ranking - Mark McGwire - Sammy Sosa rbi: # 1998 rbi ranking - Sammy Sosa - Ken Griffey php: | array( 'hr' => array( 'Mark McGwire', 'Sammy Sosa' ), 'rbi' => array( 'Sammy Sosa', 'Ken Griffey' ) ) --- test: Node for Sammy Sosa appears twice in this document spec: 2.10 yaml: | --- hr: - Mark McGwire # Following node labeled SS - &SS Sammy Sosa rbi: - *SS # Subsequent occurrence - Ken Griffey php: | array( 'hr' => array('Mark McGwire', 'Sammy Sosa'), 'rbi' => array('Sammy Sosa', 'Ken Griffey') ) --- test: Mapping between sequences todo: true spec: 2.11 yaml: | ? # PLAY SCHEDULE - Detroit Tigers - Chicago Cubs : - 2001-07-23 ? [ New York Yankees, Atlanta Braves ] : [ 2001-07-02, 2001-08-12, 2001-08-14 ] ruby: | { [ 'Detroit Tigers', 'Chicago Cubs' ] => [ Date.new( 2001, 7, 23 ) ], [ 'New York Yankees', 'Atlanta Braves' ] => [ Date.new( 2001, 7, 2 ), Date.new( 2001, 8, 12 ), Date.new( 2001, 8, 14 ) ] } syck: | struct test_node seq1[] = { { T_STR, 0, "New York Yankees" }, { T_STR, 0, "Atlanta Braves" }, end_node }; struct test_node seq2[] = { { T_STR, 0, "2001-07-02" }, { T_STR, 0, "2001-08-12" }, { T_STR, 0, "2001-08-14" }, end_node }; struct test_node seq3[] = { { T_STR, 0, "Detroit Tigers" }, { T_STR, 0, "Chicago Cubs" }, end_node }; struct test_node seq4[] = { { T_STR, 0, "2001-07-23" }, end_node }; struct test_node map[] = { { T_SEQ, 0, 0, seq3 }, { T_SEQ, 0, 0, seq4 }, { T_SEQ, 0, 0, seq1 }, { T_SEQ, 0, 0, seq2 }, end_node }; struct test_node stream[] = { { T_MAP, 0, 0, map }, end_node }; --- test: Sequence key shortcut spec: 2.12 yaml: | --- # products purchased - item : Super Hoop quantity: 1 - item : Basketball quantity: 4 - item : Big Shoes quantity: 1 php: | array ( array ( 'item' => 'Super Hoop', 'quantity' => 1, ), array ( 'item' => 'Basketball', 'quantity' => 4, ), array ( 'item' => 'Big Shoes', 'quantity' => 1, ) ) perl: | [ { item => 'Super Hoop', quantity => 1 }, { item => 'Basketball', quantity => 4 }, { item => 'Big Shoes', quantity => 1 } ] ruby: | [ { 'item' => 'Super Hoop', 'quantity' => 1 }, { 'item' => 'Basketball', 'quantity' => 4 }, { 'item' => 'Big Shoes', 'quantity' => 1 } ] python: | [ { 'item': 'Super Hoop', 'quantity': 1 }, { 'item': 'Basketball', 'quantity': 4 }, { 'item': 'Big Shoes', 'quantity': 1 } ] syck: | struct test_node map1[] = { { T_STR, 0, "item" }, { T_STR, 0, "Super Hoop" }, { T_STR, 0, "quantity" }, { T_STR, 0, "1" }, end_node }; struct test_node map2[] = { { T_STR, 0, "item" }, { T_STR, 0, "Basketball" }, { T_STR, 0, "quantity" }, { T_STR, 0, "4" }, end_node }; struct test_node map3[] = { { T_STR, 0, "item" }, { T_STR, 0, "Big Shoes" }, { T_STR, 0, "quantity" }, { T_STR, 0, "1" }, end_node }; struct test_node seq[] = { { T_MAP, 0, 0, map1 }, { T_MAP, 0, 0, map2 }, { T_MAP, 0, 0, map3 }, end_node }; struct test_node stream[] = { { T_SEQ, 0, 0, seq }, end_node }; --- test: Literal perserves newlines todo: true spec: 2.13 yaml: | # ASCII Art --- | \//||\/|| // || ||_ perl: | "\\//||\\/||\n// || ||_\n" ruby: | "\\//||\\/||\n// || ||_\n" python: | [ flushLeft( """ \//||\/|| // || ||_ """ ) ] syck: | struct test_node stream[] = { { T_STR, 0, "\\//||\\/||\n// || ||_\n" }, end_node }; --- test: Folded treats newlines as a space todo: true spec: 2.14 yaml: | --- Mark McGwire's year was crippled by a knee injury. perl: | "Mark McGwire's year was crippled by a knee injury." ruby: | "Mark McGwire's year was crippled by a knee injury." python: | [ "Mark McGwire's year was crippled by a knee injury." ] syck: | struct test_node stream[] = { { T_STR, 0, "Mark McGwire's year was crippled by a knee injury." }, end_node }; --- test: Newlines preserved for indented and blank lines todo: true spec: 2.15 yaml: | --- > Sammy Sosa completed another fine season with great stats. 63 Home Runs 0.288 Batting Average What a year! perl: | "Sammy Sosa completed another fine season with great stats.\n\n 63 Home Runs\n 0.288 Batting Average\n\nWhat a year!\n" ruby: | "Sammy Sosa completed another fine season with great stats.\n\n 63 Home Runs\n 0.288 Batting Average\n\nWhat a year!\n" python: | [ flushLeft( """ Sammy Sosa completed another fine season with great stats. 63 Home Runs 0.288 Batting Average What a year! """ ) ] syck: | struct test_node stream[] = { { T_STR, 0, "Sammy Sosa completed another fine season with great stats.\n\n 63 Home Runs\n 0.288 Batting Average\n\nWhat a year!\n" }, end_node }; --- test: Indentation determines scope spec: 2.16 yaml: | name: Mark McGwire accomplishment: > Mark set a major league home run record in 1998. stats: | 65 Home Runs 0.278 Batting Average php: | array( 'name' => 'Mark McGwire', 'accomplishment' => "Mark set a major league home run record in 1998.\n", 'stats' => "65 Home Runs\n0.278 Batting Average\n" ) --- test: Quoted scalars todo: true spec: 2.17 yaml: | unicode: "Sosa did fine.\u263A" control: "\b1998\t1999\t2000\n" hexesc: "\x0D\x0A is \r\n" single: '"Howdy!" he cried.' quoted: ' # not a ''comment''.' tie-fighter: '|\-*-/|' ruby: | { "tie-fighter" => "|\\-*-/|", "control"=>"\0101998\t1999\t2000\n", "unicode"=>"Sosa did fine." + ["263A".hex ].pack('U*'), "quoted"=>" # not a 'comment'.", "single"=>"\"Howdy!\" he cried.", "hexesc"=>"\r\n is \r\n" } --- test: Multiline flow scalars todo: true spec: 2.18 yaml: | plain: This unquoted scalar spans many lines. quoted: "So does this quoted scalar.\n" ruby: | { 'plain' => 'This unquoted scalar spans many lines.', 'quoted' => "So does this quoted scalar.\n" } --- test: Integers spec: 2.19 yaml: | canonical: 12345 octal: 014 hexadecimal: 0xC php: | array( 'canonical' => 12345, 'octal' => 014, 'hexadecimal' => 0xC ) --- test: Decimal Integer deprecated: true spec: 2.19 yaml: | decimal: +12,345 php: | array( 'decimal' => 12345.0, ) --- # FIX: spec shows parens around -inf and NaN test: Floating point spec: 2.20 yaml: | canonical: 1.23015e+3 exponential: 12.3015e+02 negative infinity: -.inf not a number: .NaN float as whole number: !!float 1 php: | array( 'canonical' => 1230.15, 'exponential' => 1230.15, 'negative infinity' => log(0), 'not a number' => -log(0), 'float as whole number' => (float) 1 ) --- test: Fixed Floating point deprecated: true spec: 2.20 yaml: | fixed: 1,230.15 php: | array( 'fixed' => 1230.15, ) --- test: Miscellaneous spec: 2.21 yaml: | null: ~ true: true false: false string: '12345' php: | array( '' => null, 1 => true, 0 => false, 'string' => '12345' ) --- test: Timestamps todo: true spec: 2.22 yaml: | canonical: 2001-12-15T02:59:43.1Z iso8601: 2001-12-14t21:59:43.10-05:00 spaced: 2001-12-14 21:59:43.10 -05:00 date: 2002-12-14 # Time is noon UTC php: | array( 'canonical' => YAML::mktime( 2001, 12, 15, 2, 59, 43, 0.10 ), 'iso8601' => YAML::mktime( 2001, 12, 14, 21, 59, 43, 0.10, "-05:00" ), 'spaced' => YAML::mktime( 2001, 12, 14, 21, 59, 43, 0.10, "-05:00" ), 'date' => Date.new( 2002, 12, 14 ) ) --- test: legacy Timestamps test todo: true spec: legacy D4 yaml: | canonical: 2001-12-15T02:59:43.00Z iso8601: 2001-02-28t21:59:43.00-05:00 spaced: 2001-12-14 21:59:43.00 -05:00 date: 2002-12-14 php: | array( 'canonical' => Time::utc( 2001, 12, 15, 2, 59, 43, 0 ), 'iso8601' => YAML::mktime( 2001, 2, 28, 21, 59, 43, 0, "-05:00" ), 'spaced' => YAML::mktime( 2001, 12, 14, 21, 59, 43, 0, "-05:00" ), 'date' => Date.new( 2002, 12, 14 ) ) --- test: Various explicit families todo: true spec: 2.23 yaml: | not-date: !str 2002-04-28 picture: !binary | R0lGODlhDAAMAIQAAP//9/X 17unp5WZmZgAAAOfn515eXv Pz7Y6OjuDg4J+fn5OTk6enp 56enmleECcgggoBADs= application specific tag: !!something | The semantics of the tag above may be different for different documents. ruby-setup: | YAML.add_private_type( "something" ) do |type, val| "SOMETHING: #{val}" end ruby: | { 'not-date' => '2002-04-28', 'picture' => "GIF89a\f\000\f\000\204\000\000\377\377\367\365\365\356\351\351\345fff\000\000\000\347\347\347^^^\363\363\355\216\216\216\340\340\340\237\237\237\223\223\223\247\247\247\236\236\236i^\020' \202\n\001\000;", 'application specific tag' => "SOMETHING: The semantics of the tag\nabove may be different for\ndifferent documents.\n" } --- test: Application specific family todo: true spec: 2.24 yaml: | # Establish a tag prefix --- !clarkevans.com,2002/graph/^shape # Use the prefix: shorthand for # !clarkevans.com,2002/graph/circle - !^circle center: &ORIGIN {x: 73, 'y': 129} radius: 7 - !^line # !clarkevans.com,2002/graph/line start: *ORIGIN finish: { x: 89, 'y': 102 } - !^label start: *ORIGIN color: 0xFFEEBB value: Pretty vector drawing. ruby-setup: | YAML.add_domain_type( "clarkevans.com,2002", 'graph/shape' ) { |type, val| if Array === val val << "Shape Container" val else raise YAML::Error, "Invalid graph of class #{ val.class }: " + val.inspect end } one_shape_proc = Proc.new { |type, val| scheme, domain, type = type.split( /:/, 3 ) if val.is_a? ::Hash val['TYPE'] = "Shape: #{type}" val else raise YAML::Error, "Invalid graph of class #{ val.class }: " + val.inspect end } YAML.add_domain_type( "clarkevans.com,2002", 'graph/circle', &one_shape_proc ) YAML.add_domain_type( "clarkevans.com,2002", 'graph/line', &one_shape_proc ) YAML.add_domain_type( "clarkevans.com,2002", 'graph/label', &one_shape_proc ) ruby: | [ { "radius" => 7, "center"=> { "x" => 73, "y" => 129 }, "TYPE" => "Shape: graph/circle" }, { "finish" => { "x" => 89, "y" => 102 }, "TYPE" => "Shape: graph/line", "start" => { "x" => 73, "y" => 129 } }, { "TYPE" => "Shape: graph/label", "value" => "Pretty vector drawing.", "start" => { "x" => 73, "y" => 129 }, "color" => 16772795 }, "Shape Container" ] # --- # test: Unordered set # spec: 2.25 # yaml: | # # sets are represented as a # # mapping where each key is # # associated with the empty string # --- !set # ? Mark McGwire # ? Sammy Sosa # ? Ken Griff --- test: Ordered mappings todo: true spec: 2.26 yaml: | # ordered maps are represented as # a sequence of mappings, with # each mapping having one key --- !omap - Mark McGwire: 65 - Sammy Sosa: 63 - Ken Griffy: 58 ruby: | YAML::Omap[ 'Mark McGwire', 65, 'Sammy Sosa', 63, 'Ken Griffy', 58 ] --- test: Invoice dump_skip: true spec: 2.27 yaml: | --- !clarkevans.com,2002/^invoice invoice: 34843 date : 2001-01-23 bill-to: &id001 given : Chris family : Dumars address: lines: | 458 Walkman Dr. Suite #292 city : Royal Oak state : MI postal : 48046 ship-to: *id001 product: - sku : BL394D quantity : 4 description : Basketball price : 450.00 - sku : BL4438H quantity : 1 description : Super Hoop price : 2392.00 tax : 251.42 total: 4443.52 comments: > Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338. php: | array( 'invoice' => 34843, 'date' => gmmktime(0, 0, 0, 1, 23, 2001), 'bill-to' => array( 'given' => 'Chris', 'family' => 'Dumars', 'address' => array( 'lines' => "458 Walkman Dr.\nSuite #292\n", 'city' => 'Royal Oak', 'state' => 'MI', 'postal' => 48046 ) ) , 'ship-to' => array( 'given' => 'Chris', 'family' => 'Dumars', 'address' => array( 'lines' => "458 Walkman Dr.\nSuite #292\n", 'city' => 'Royal Oak', 'state' => 'MI', 'postal' => 48046 ) ) , 'product' => array( array( 'sku' => 'BL394D', 'quantity' => 4, 'description' => 'Basketball', 'price' => 450.00 ), array( 'sku' => 'BL4438H', 'quantity' => 1, 'description' => 'Super Hoop', 'price' => 2392.00 ) ), 'tax' => 251.42, 'total' => 4443.52, 'comments' => "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338.\n" ) --- test: Log file todo: true spec: 2.28 yaml: | --- Time: 2001-11-23 15:01:42 -05:00 User: ed Warning: > This is an error message for the log file --- Time: 2001-11-23 15:02:31 -05:00 User: ed Warning: > A slightly different error message. --- Date: 2001-11-23 15:03:17 -05:00 User: ed Fatal: > Unknown variable "bar" Stack: - file: TopClass.py line: 23 code: | x = MoreObject("345\n") - file: MoreClass.py line: 58 code: |- foo = bar ruby: | y = YAML::Stream.new y.add( { 'Time' => YAML::mktime( 2001, 11, 23, 15, 01, 42, 00, "-05:00" ), 'User' => 'ed', 'Warning' => "This is an error message for the log file\n" } ) y.add( { 'Time' => YAML::mktime( 2001, 11, 23, 15, 02, 31, 00, "-05:00" ), 'User' => 'ed', 'Warning' => "A slightly different error message.\n" } ) y.add( { 'Date' => YAML::mktime( 2001, 11, 23, 15, 03, 17, 00, "-05:00" ), 'User' => 'ed', 'Fatal' => "Unknown variable \"bar\"\n", 'Stack' => [ { 'file' => 'TopClass.py', 'line' => 23, 'code' => "x = MoreObject(\"345\\n\")\n" }, { 'file' => 'MoreClass.py', 'line' => 58, 'code' => "foo = bar" } ] } ) documents: 3 --- test: Throwaway comments yaml: | ### These are four throwaway comment ### ### lines (the second line is empty). ### this: | # Comments may trail lines. contains three lines of text. The third one starts with a # character. This isn't a comment. # These are three throwaway comment # lines (the first line is empty). php: | array( 'this' => "contains three lines of text.\nThe third one starts with a\n# character. This isn't a comment.\n" ) --- test: Document with a single value todo: true yaml: | --- > This YAML stream contains a single text value. The next stream is a log file - a sequence of log entries. Adding an entry to the log is a simple matter of appending it at the end. ruby: | "This YAML stream contains a single text value. The next stream is a log file - a sequence of log entries. Adding an entry to the log is a simple matter of appending it at the end.\n" --- test: Document stream todo: true yaml: | --- at: 2001-08-12 09:25:00.00 Z type: GET HTTP: '1.0' url: '/index.html' --- at: 2001-08-12 09:25:10.00 Z type: GET HTTP: '1.0' url: '/toc.html' ruby: | y = YAML::Stream.new y.add( { 'at' => Time::utc( 2001, 8, 12, 9, 25, 00 ), 'type' => 'GET', 'HTTP' => '1.0', 'url' => '/index.html' } ) y.add( { 'at' => Time::utc( 2001, 8, 12, 9, 25, 10 ), 'type' => 'GET', 'HTTP' => '1.0', 'url' => '/toc.html' } ) documents: 2 --- test: Top level mapping yaml: | # This stream is an example of a top-level mapping. invoice : 34843 date : 2001-01-23 total : 4443.52 php: | array( 'invoice' => 34843, 'date' => gmmktime(0, 0, 0, 1, 23, 2001), 'total' => 4443.52 ) --- test: Single-line documents todo: true yaml: | # The following is a sequence of three documents. # The first contains an empty mapping, the second # an empty sequence, and the last an empty string. --- {} --- [ ] --- '' ruby: | y = YAML::Stream.new y.add( {} ) y.add( [] ) y.add( '' ) documents: 3 --- test: Document with pause todo: true yaml: | # A communication channel based on a YAML stream. --- sent at: 2002-06-06 11:46:25.10 Z payload: Whatever # Receiver can process this as soon as the following is sent: ... # Even if the next message is sent long after: --- sent at: 2002-06-06 12:05:53.47 Z payload: Whatever ... ruby: | y = YAML::Stream.new y.add( { 'sent at' => YAML::mktime( 2002, 6, 6, 11, 46, 25, 0.10 ), 'payload' => 'Whatever' } ) y.add( { "payload" => "Whatever", "sent at" => YAML::mktime( 2002, 6, 6, 12, 5, 53, 0.47 ) } ) documents: 2 --- test: Explicit typing yaml: | integer: 12 also int: ! "12" string: !str 12 php: | array( 'integer' => 12, 'also int' => 12, 'string' => '12' ) --- test: Private types todo: true yaml: | # Both examples below make use of the 'x-private:ball' # type family URI, but with different semantics. --- pool: !!ball number: 8 color: black --- bearing: !!ball material: steel ruby: | y = YAML::Stream.new y.add( { 'pool' => YAML::PrivateType.new( 'ball', { 'number' => 8, 'color' => 'black' } ) } ) y.add( { 'bearing' => YAML::PrivateType.new( 'ball', { 'material' => 'steel' } ) } ) documents: 2 --- test: Type family under yaml.org yaml: | # The URI is 'tag:yaml.org,2002:str' - !str a Unicode string php: | array( 'a Unicode string' ) --- test: Type family under perl.yaml.org todo: true yaml: | # The URI is 'tag:perl.yaml.org,2002:Text::Tabs' - !perl/Text::Tabs {} ruby: | [ YAML::DomainType.new( 'perl.yaml.org,2002', 'Text::Tabs', {} ) ] --- test: Type family under clarkevans.com todo: true yaml: | # The URI is 'tag:clarkevans.com,2003-02:timesheet' - !clarkevans.com,2003-02/timesheet {} ruby: | [ YAML::DomainType.new( 'clarkevans.com,2003-02', 'timesheet', {} ) ] --- test: URI Escaping todo: true yaml: | same: - !domain.tld,2002/type\x30 value - !domain.tld,2002/type0 value different: # As far as the YAML parser is concerned - !domain.tld,2002/type%30 value - !domain.tld,2002/type0 value ruby-setup: | YAML.add_domain_type( "domain.tld,2002", "type0" ) { |type, val| "ONE: #{val}" } YAML.add_domain_type( "domain.tld,2002", "type%30" ) { |type, val| "TWO: #{val}" } ruby: | { 'same' => [ 'ONE: value', 'ONE: value' ], 'different' => [ 'TWO: value', 'ONE: value' ] } --- test: URI Prefixing todo: true yaml: | # 'tag:domain.tld,2002:invoice' is some type family. invoice: !domain.tld,2002/^invoice # 'seq' is shorthand for 'tag:yaml.org,2002:seq'. # This does not effect '^customer' below # because it is does not specify a prefix. customers: !seq # '^customer' is shorthand for the full # notation 'tag:domain.tld,2002:customer'. - !^customer given : Chris family : Dumars ruby-setup: | YAML.add_domain_type( "domain.tld,2002", /(invoice|customer)/ ) { |type, val| if val.is_a? ::Hash scheme, domain, type = type.split( /:/, 3 ) val['type'] = "domain #{type}" val else raise YAML::Error, "Not a Hash in domain.tld/invoice: " + val.inspect end } ruby: | { "invoice"=> { "customers"=> [ { "given"=>"Chris", "type"=>"domain customer", "family"=>"Dumars" } ], "type"=>"domain invoice" } } --- test: Overriding anchors yaml: | anchor : &A001 This scalar has an anchor. override : &A001 > The alias node below is a repeated use of this value. alias : *A001 php: | array( 'anchor' => 'This scalar has an anchor.', 'override' => "The alias node below is a repeated use of this value.\n", 'alias' => "The alias node below is a repeated use of this value.\n" ) --- test: Flow and block formatting todo: true yaml: | empty: [] flow: [ one, two, three # May span lines, , four, # indentation is five ] # mostly ignored. block: - First item in top sequence - - Subordinate sequence entry - > A folded sequence entry - Sixth item in top sequence ruby: | { 'empty' => [], 'flow' => [ 'one', 'two', 'three', 'four', 'five' ], 'block' => [ 'First item in top sequence', [ 'Subordinate sequence entry' ], "A folded sequence entry\n", 'Sixth item in top sequence' ] } --- test: Complete mapping test todo: true yaml: | empty: {} flow: { one: 1, two: 2 } spanning: { one: 1, two: 2 } block: first : First entry second: key: Subordinate mapping third: - Subordinate sequence - { } - Previous mapping is empty. - A key: value pair in a sequence. A second: key:value pair. - The previous entry is equal to the following one. - A key: value pair in a sequence. A second: key:value pair. !float 12 : This key is a float. ? > ? : This key had to be protected. "\a" : This key had to be escaped. ? > This is a multi-line folded key : Whose value is also multi-line. ? this also works as a key : with a value at the next line. ? - This key - is a sequence : - With a sequence value. ? This: key is a: mapping : with a: mapping value. ruby: | { 'empty' => {}, 'flow' => { 'one' => 1, 'two' => 2 }, 'spanning' => { 'one' => 1, 'two' => 2 }, 'block' => { 'first' => 'First entry', 'second' => { 'key' => 'Subordinate mapping' }, 'third' => [ 'Subordinate sequence', {}, 'Previous mapping is empty.', { 'A key' => 'value pair in a sequence.', 'A second' => 'key:value pair.' }, 'The previous entry is equal to the following one.', { 'A key' => 'value pair in a sequence.', 'A second' => 'key:value pair.' } ], 12.0 => 'This key is a float.', "?\n" => 'This key had to be protected.', "\a" => 'This key had to be escaped.', "This is a multi-line folded key\n" => "Whose value is also multi-line.", 'this also works as a key' => 'with a value at the next line.', [ 'This key', 'is a sequence' ] => [ 'With a sequence value.' ] } } # Couldn't recreate map exactly, so we'll do a detailed check to be sure it's entact obj_y['block'].keys.each { |k| if Hash === k v = obj_y['block'][k] if k['This'] == 'key' and k['is a'] == 'mapping' and v['with a'] == 'mapping value.' obj_r['block'][k] = v end end } --- test: Literal explicit indentation yaml: | # Explicit indentation must # be given in all the three # following cases. leading spaces: |2 This value starts with four spaces. leading line break: |2 This value starts with a line break. leading comment indicator: |2 # first line starts with a # character. # Explicit indentation may # also be given when it is # not required. redundant: |2 This value is indented 2 spaces. php: | array( 'leading spaces' => " This value starts with four spaces.\n", 'leading line break' => "\nThis value starts with a line break.\n", 'leading comment indicator' => "# first line starts with a\n# character.\n", 'redundant' => "This value is indented 2 spaces.\n" ) --- test: Chomping and keep modifiers yaml: | clipped: | This has one newline. same as "clipped" above: "This has one newline.\n" stripped: |- This has no newline. same as "stripped" above: "This has no newline." kept: |+ This has two newlines. same as "kept" above: "This has two newlines.\n\n" php: | array( 'clipped' => "This has one newline.\n", 'same as "clipped" above' => "This has one newline.\n", 'stripped' => 'This has no newline.', 'same as "stripped" above' => 'This has no newline.', 'kept' => "This has two newlines.\n\n", 'same as "kept" above' => "This has two newlines.\n\n" ) --- test: Literal combinations todo: true yaml: | empty: | literal: | The \ ' " characters may be freely used. Leading white space is significant. Line breaks are significant. Thus this value contains one empty line and ends with a single line break, but does not start with one. is equal to: "The \\ ' \" characters may \ be\nfreely used. Leading white\n space \ is significant.\n\nLine breaks are \ significant.\nThus this value contains \ one\nempty line and ends with a\nsingle \ line break, but does\nnot start with one.\n" # Comments may follow a block # scalar value. They must be # less indented. # Modifiers may be combined in any order. indented and chomped: |2- This has no newline. also written as: |-2 This has no newline. both are equal to: " This has no newline." php: | array( 'empty' => '', 'literal' => "The \\ ' \" characters may be\nfreely used. Leading white\n space " + "is significant.\n\nLine breaks are significant.\nThus this value contains one\n" + "empty line and ends with a\nsingle line break, but does\nnot start with one.\n", 'is equal to' => "The \\ ' \" characters may be\nfreely used. Leading white\n space " + "is significant.\n\nLine breaks are significant.\nThus this value contains one\n" + "empty line and ends with a\nsingle line break, but does\nnot start with one.\n", 'indented and chomped' => ' This has no newline.', 'also written as' => ' This has no newline.', 'both are equal to' => ' This has no newline.' ) --- test: Folded combinations todo: true yaml: | empty: > one paragraph: > Line feeds are converted to spaces, so this value contains no line breaks except for the final one. multiple paragraphs: >2 An empty line, either at the start or in the value: Is interpreted as a line break. Thus this value contains three line breaks. indented text: > This is a folded paragraph followed by a list: * first entry * second entry Followed by another folded paragraph, another list: * first entry * second entry And a final folded paragraph. above is equal to: | This is a folded paragraph followed by a list: * first entry * second entry Followed by another folded paragraph, another list: * first entry * second entry And a final folded paragraph. # Explicit comments may follow # but must be less indented. php: | array( 'empty' => '', 'one paragraph' => 'Line feeds are converted to spaces, so this value'. " contains no line breaks except for the final one.\n", 'multiple paragraphs' => "\nAn empty line, either at the start or in the value:\n". "Is interpreted as a line break. Thus this value contains three line breaks.\n", 'indented text' => "This is a folded paragraph followed by a list:\n". " * first entry\n * second entry\nFollowed by another folded paragraph, ". "another list:\n\n * first entry\n\n * second entry\n\nAnd a final folded paragraph.\n", 'above is equal to' => "This is a folded paragraph followed by a list:\n". " * first entry\n * second entry\nFollowed by another folded paragraph, ". "another list:\n\n * first entry\n\n * second entry\n\nAnd a final folded paragraph.\n" ) --- test: Single quotes todo: true yaml: | empty: '' second: '! : \ etc. can be used freely.' third: 'a single quote '' must be escaped.' span: 'this contains six spaces and one line break' is same as: "this contains six spaces\nand one line break" php: | array( 'empty' => '', 'second' => '! : \\ etc. can be used freely.', 'third' => "a single quote ' must be escaped.", 'span' => "this contains six spaces\nand one line break", 'is same as' => "this contains six spaces\nand one line break" ) --- test: Double quotes todo: true yaml: | empty: "" second: "! : etc. can be used freely." third: "a \" or a \\ must be escaped." fourth: "this value ends with an LF.\n" span: "this contains four \ spaces" is equal to: "this contains four spaces" php: | array( 'empty' => '', 'second' => '! : etc. can be used freely.', 'third' => 'a " or a \\ must be escaped.', 'fourth' => "this value ends with an LF.\n", 'span' => "this contains four spaces", 'is equal to' => "this contains four spaces" ) --- test: Unquoted strings todo: true yaml: | first: There is no unquoted empty string. second: 12 ## This is an integer. third: !str 12 ## This is a string. span: this contains six spaces and one line break indicators: this has no comments. #:foo and bar# are both text. flow: [ can span lines, # comment like this ] note: { one-line keys: but multi-line values } php: | array( 'first' => 'There is no unquoted empty string.', 'second' => 12, 'third' => '12', 'span' => "this contains six spaces\nand one line break", 'indicators' => "this has no comments. #:foo and bar# are both text.", 'flow' => [ 'can span lines', 'like this' ], 'note' => { 'one-line keys' => 'but multi-line values' } ) --- test: Spanning sequences todo: true yaml: | # The following are equal seqs # with different identities. flow: [ one, two ] spanning: [ one, two ] block: - one - two php: | array( 'flow' => [ 'one', 'two' ], 'spanning' => [ 'one', 'two' ], 'block' => [ 'one', 'two' ] ) --- test: Flow mappings yaml: | # The following are equal maps # with different identities. flow: { one: 1, two: 2 } block: one: 1 two: 2 php: | array( 'flow' => array( 'one' => 1, 'two' => 2 ), 'block' => array( 'one' => 1, 'two' => 2 ) ) --- test: Representations of 12 todo: true yaml: | - 12 # An integer # The following scalars # are loaded to the # string value '1' '2'. - !str 12 - '12' - "12" - "\ 1\ 2\ " # Strings containing paths and regexps can be unquoted: - /foo/bar - d:/foo/bar - foo/bar - /a.*b/ php: | array( 12, '12', '12', '12', '12', '/foo/bar', 'd:/foo/bar', 'foo/bar', '/a.*b/' ) --- test: "Null" todo: true yaml: | canonical: ~ english: null # This sequence has five # entries, two with values. sparse: - ~ - 2nd entry - Null - 4th entry - four: This mapping has five keys, only two with values. php: | array ( 'canonical' => null, 'english' => null, 'sparse' => array( null, '2nd entry', null, '4th entry', null ]), 'four' => 'This mapping has five keys, only two with values.' ) --- test: Omap todo: true yaml: | # Explicitly typed dictionary. Bestiary: !omap - aardvark: African pig-like ant eater. Ugly. - anteater: South-American ant eater. Two species. - anaconda: South-American constrictor snake. Scary. # Etc. ruby: | { 'Bestiary' => YAML::Omap[ 'aardvark', 'African pig-like ant eater. Ugly.', 'anteater', 'South-American ant eater. Two species.', 'anaconda', 'South-American constrictor snake. Scary.' ] } --- test: Pairs todo: true yaml: | # Explicitly typed pairs. tasks: !pairs - meeting: with team. - meeting: with boss. - break: lunch. - meeting: with client. ruby: | { 'tasks' => YAML::Pairs[ 'meeting', 'with team.', 'meeting', 'with boss.', 'break', 'lunch.', 'meeting', 'with client.' ] } --- test: Set todo: true yaml: | # Explicitly typed set. baseball players: !set Mark McGwire: Sammy Sosa: Ken Griffey: ruby: | { 'baseball players' => YAML::Set[ 'Mark McGwire', nil, 'Sammy Sosa', nil, 'Ken Griffey', nil ] } --- test: Boolean yaml: | false: used as key logical: true answer: false php: | array( false => 'used as key', 'logical' => true, 'answer' => false ) --- test: Integer yaml: | canonical: 12345 octal: 014 hexadecimal: 0xC php: | array( 'canonical' => 12345, 'octal' => 12, 'hexadecimal' => 12 ) --- test: Decimal deprecated: true yaml: | decimal: +12,345 php: | array( 'decimal' => 12345.0, ) --- test: Fixed Float deprecated: true yaml: | fixed: 1,230.15 php: | array( 'fixed' => 1230.15, ) --- test: Float yaml: | canonical: 1.23015e+3 exponential: 12.3015e+02 negative infinity: -.inf not a number: .NaN php: | array( 'canonical' => 1230.15, 'exponential' => 1230.15, 'negative infinity' => log(0), 'not a number' => -log(0) ) --- test: Timestamp todo: true yaml: | canonical: 2001-12-15T02:59:43.1Z valid iso8601: 2001-12-14t21:59:43.10-05:00 space separated: 2001-12-14 21:59:43.10 -05:00 date (noon UTC): 2002-12-14 ruby: | array( 'canonical' => YAML::mktime( 2001, 12, 15, 2, 59, 43, 0.10 ), 'valid iso8601' => YAML::mktime( 2001, 12, 14, 21, 59, 43, 0.10, "-05:00" ), 'space separated' => YAML::mktime( 2001, 12, 14, 21, 59, 43, 0.10, "-05:00" ), 'date (noon UTC)' => Date.new( 2002, 12, 14 ) ) --- test: Binary todo: true yaml: | canonical: !binary "\ R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5\ OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+\ +f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC\ AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs=" base64: !binary | R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5 OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+ +f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs= description: > The binary value above is a tiny arrow encoded as a gif image. ruby-setup: | arrow_gif = "GIF89a\f\000\f\000\204\000\000\377\377\367\365\365\356\351\351\345fff\000\000\000\347\347\347^^^\363\363\355\216\216\216\340\340\340\237\237\237\223\223\223\247\247\247\236\236\236iiiccc\243\243\243\204\204\204\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371\377\376\371!\376\016Made with GIMP\000,\000\000\000\000\f\000\f\000\000\005, \216\2010\236\343@\024\350i\020\304\321\212\010\034\317\200M$z\357\3770\205p\270\2601f\r\e\316\001\303\001\036\020' \202\n\001\000;" ruby: | { 'canonical' => arrow_gif, 'base64' => arrow_gif, 'description' => "The binary value above is a tiny arrow encoded as a gif image.\n" } --- test: Merge key todo: true yaml: | --- - &CENTER { x: 1, y: 2 } - &LEFT { x: 0, y: 2 } - &BIG { r: 10 } - &SMALL { r: 1 } # All the following maps are equal: - # Explicit keys x: 1 y: 2 r: 10 label: center/big - # Merge one map << : *CENTER r: 10 label: center/big - # Merge multiple maps << : [ *CENTER, *BIG ] label: center/big - # Override << : [ *BIG, *LEFT, *SMALL ] x: 1 label: center/big ruby-setup: | center = { 'x' => 1, 'y' => 2 } left = { 'x' => 0, 'y' => 2 } big = { 'r' => 10 } small = { 'r' => 1 } node1 = { 'x' => 1, 'y' => 2, 'r' => 10, 'label' => 'center/big' } node2 = center.dup node2.update( { 'r' => 10, 'label' => 'center/big' } ) node3 = big.dup node3.update( center ) node3.update( { 'label' => 'center/big' } ) node4 = small.dup node4.update( left ) node4.update( big ) node4.update( { 'x' => 1, 'label' => 'center/big' } ) ruby: | [ center, left, big, small, node1, node2, node3, node4 ] --- test: Default key todo: true yaml: | --- # Old schema link with: - library1.dll - library2.dll --- # New schema link with: - = : library1.dll version: 1.2 - = : library2.dll version: 2.3 ruby: | y = YAML::Stream.new y.add( { 'link with' => [ 'library1.dll', 'library2.dll' ] } ) obj_h = Hash[ 'version' => 1.2 ] obj_h.default = 'library1.dll' obj_h2 = Hash[ 'version' => 2.3 ] obj_h2.default = 'library2.dll' y.add( { 'link with' => [ obj_h, obj_h2 ] } ) documents: 2 --- test: Special keys todo: true yaml: | "!": These three keys "&": had to be quoted "=": and are normal strings. # NOTE: the following node should NOT be serialized this way. encoded node : !special '!' : '!type' !special|canonical '&' : 12 = : value # The proper way to serialize the above node is as follows: node : !!type &12 value ruby: | { '!' => 'These three keys', '&' => 'had to be quoted', '=' => 'and are normal strings.', 'encoded node' => YAML::PrivateType.new( 'type', 'value' ), 'node' => YAML::PrivateType.new( 'type', 'value' ) } symfony/yaml/Tests/Fixtures/YtsFlowCollections.yml 0000604 00000003130 15247160545 0016460 0 ustar 00 --- test: Simple Inline Array brief: > Sequences can be contained on a single line, using the inline syntax. Separate each entry with commas and enclose in square brackets. yaml: | seq: [ a, b, c ] php: | array('seq' => array('a', 'b', 'c')) --- test: Simple Inline Hash brief: > Mapping can also be contained on a single line, using the inline syntax. Each key-value pair is separated by a colon, with a comma between each entry in the mapping. Enclose with curly braces. yaml: | hash: { name: Steve, foo: bar } php: | array('hash' => array('name' => 'Steve', 'foo' => 'bar')) --- test: Multi-line Inline Collections todo: true brief: > Both inline sequences and inline mappings can span multiple lines, provided that you indent the additional lines. yaml: | languages: [ Ruby, Perl, Python ] websites: { YAML: yaml.org, Ruby: ruby-lang.org, Python: python.org, Perl: use.perl.org } php: | array( 'languages' => array('Ruby', 'Perl', 'Python'), 'websites' => array( 'YAML' => 'yaml.org', 'Ruby' => 'ruby-lang.org', 'Python' => 'python.org', 'Perl' => 'use.perl.org' ) ) --- test: Commas in Values (not in the spec!) todo: true brief: > List items in collections are delimited by commas, but there must be a space after each comma. This allows you to add numbers without quoting. yaml: | attendances: [ 45,123, 70,000, 17,222 ] php: | array('attendances' => array(45123, 70000, 17222)) symfony/yaml/Tests/Fixtures/YtsTypeTransfers.yml 0000604 00000016755 15247160545 0016204 0 ustar 00 --- %YAML:1.0 test: Strings brief: > Any group of characters beginning with an alphabetic or numeric character is a string, unless it belongs to one of the groups below (such as an Integer or Time). yaml: | String php: | 'String' --- test: String characters brief: > A string can contain any alphabetic or numeric character, along with many punctuation characters, including the period, dash, space, quotes, exclamation, and question mark. yaml: | - What's Yaml? - It's for writing data structures in plain text. - And? - And what? That's not good enough for you? - No, I mean, "And what about Yaml?" - Oh, oh yeah. Uh.. Yaml for Ruby. php: | array( "What's Yaml?", "It's for writing data structures in plain text.", "And?", "And what? That's not good enough for you?", "No, I mean, \"And what about Yaml?\"", "Oh, oh yeah. Uh.. Yaml for Ruby." ) --- test: Indicators in Strings brief: > Be careful using indicators in strings. In particular, the comma, colon, and pound sign must be used carefully. yaml: | the colon followed by space is an indicator: but is a string:right here same for the pound sign: here we have it#in a string the comma can, honestly, be used in most cases: [ but not in, inline collections ] php: | array( 'the colon followed by space is an indicator' => 'but is a string:right here', 'same for the pound sign' => 'here we have it#in a string', 'the comma can, honestly, be used in most cases' => array('but not in', 'inline collections') ) --- test: Forcing Strings brief: > Any YAML type can be forced into a string using the explicit !str method. yaml: | date string: !str 2001-08-01 number string: !str 192 php: | array( 'date string' => '2001-08-01', 'number string' => '192' ) --- test: Single-quoted Strings brief: > You can also enclose your strings within single quotes, which allows use of slashes, colons, and other indicators freely. Inside single quotes, you can represent a single quote in your string by using two single quotes next to each other. yaml: | all my favorite symbols: '#:!/%.)' a few i hate: '&(*' why do i hate them?: 'it''s very hard to explain' entities: '£ me' php: | array( 'all my favorite symbols' => '#:!/%.)', 'a few i hate' => '&(*', 'why do i hate them?' => 'it\'s very hard to explain', 'entities' => '£ me' ) --- test: Double-quoted Strings brief: > Enclosing strings in double quotes allows you to use escapings to represent ASCII and Unicode characters. yaml: | i know where i want my line breaks: "one here\nand another here\n" php: | array( 'i know where i want my line breaks' => "one here\nand another here\n" ) --- test: Multi-line Quoted Strings todo: true brief: > Both single- and double-quoted strings may be carried on to new lines in your YAML document. They must be indented a step and indentation is interpreted as a single space. yaml: | i want a long string: "so i'm going to let it go on and on to other lines until i end it with a quote." php: | array('i want a long string' => "so i'm going to ". "let it go on and on to other lines ". "until i end it with a quote." ) --- test: Plain scalars todo: true brief: > Unquoted strings may also span multiple lines, if they are free of YAML space indicators and indented. yaml: | - My little toe is broken in two places; - I'm crazy to have skied this way; - I'm not the craziest he's seen, since there was always the German guy who skied for 3 hours on a broken shin bone (just below the kneecap); - Nevertheless, second place is respectable, and he doesn't recommend going for the record; - He's going to put my foot in plaster for a month; - This would impair my skiing ability somewhat for the duration, as can be imagined. php: | array( "My little toe is broken in two places;", "I'm crazy to have skied this way;", "I'm not the craziest he's seen, since there was always ". "the German guy who skied for 3 hours on a broken shin ". "bone (just below the kneecap);", "Nevertheless, second place is respectable, and he doesn't ". "recommend going for the record;", "He's going to put my foot in plaster for a month;", "This would impair my skiing ability somewhat for the duration, ". "as can be imagined." ) --- test: 'Null' brief: > You can use the tilde '~' character for a null value. yaml: | name: Mr. Show hosted by: Bob and David date of next season: ~ php: | array( 'name' => 'Mr. Show', 'hosted by' => 'Bob and David', 'date of next season' => null ) --- test: Boolean brief: > You can use 'true' and 'false' for Boolean values. yaml: | Is Gus a Liar?: true Do I rely on Gus for Sustenance?: false php: | array( 'Is Gus a Liar?' => true, 'Do I rely on Gus for Sustenance?' => false ) --- test: Integers dump_skip: true brief: > An integer is a series of numbers, optionally starting with a positive or negative sign. Integers may also contain commas for readability. yaml: | zero: 0 simple: 12 php: | array( 'zero' => 0, 'simple' => 12, ) --- test: Positive Big Integer deprecated: true dump_skip: true brief: > An integer is a series of numbers, optionally starting with a positive or negative sign. Integers may also contain commas for readability. yaml: | one-thousand: 1,000 php: | array( 'one-thousand' => 1000.0, ) --- test: Negative Big Integer deprecated: true dump_skip: true brief: > An integer is a series of numbers, optionally starting with a positive or negative sign. Integers may also contain commas for readability. yaml: | negative one-thousand: -1,000 php: | array( 'negative one-thousand' => -1000.0 ) --- test: Integers as Map Keys brief: > An integer can be used a dictionary key. yaml: | 1: one 2: two 3: three php: | array( 1 => 'one', 2 => 'two', 3 => 'three' ) --- test: Floats dump_skip: true brief: > Floats are represented by numbers with decimals, allowing for scientific notation, as well as positive and negative infinity and "not a number." yaml: | a simple float: 2.00 scientific notation: 1.00009e+3 php: | array( 'a simple float' => 2.0, 'scientific notation' => 1000.09 ) --- test: Larger Float dump_skip: true deprecated: true brief: > Floats are represented by numbers with decimals, allowing for scientific notation, as well as positive and negative infinity and "not a number." yaml: | larger float: 1,000.09 php: | array( 'larger float' => 1000.09, ) --- test: Time todo: true brief: > You can represent timestamps by using ISO8601 format, or a variation which allows spaces between the date, time and time zone. yaml: | iso8601: 2001-12-14t21:59:43.10-05:00 space separated: 2001-12-14 21:59:43.10 -05:00 php: | array( 'iso8601' => mktime( 2001, 12, 14, 21, 59, 43, 0.10, "-05:00" ), 'space separated' => mktime( 2001, 12, 14, 21, 59, 43, 0.10, "-05:00" ) ) --- test: Date todo: true brief: > A date can be represented by its year, month and day in ISO8601 order. yaml: | 1976-07-31 php: | date( 1976, 7, 31 ) symfony/yaml/Tests/DumperTest.php 0000604 00000024452 15247160545 0013135 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Yaml\Tests; use PHPUnit\Framework\TestCase; use Symfony\Component\Yaml\Parser; use Symfony\Component\Yaml\Dumper; use Symfony\Component\Yaml\Yaml; class DumperTest extends TestCase { protected $parser; protected $dumper; protected $path; protected $array = array( '' => 'bar', 'foo' => '#bar', 'foo\'bar' => array(), 'bar' => array(1, 'foo'), 'foobar' => array( 'foo' => 'bar', 'bar' => array(1, 'foo'), 'foobar' => array( 'foo' => 'bar', 'bar' => array(1, 'foo'), ), ), ); protected function setUp() { $this->parser = new Parser(); $this->dumper = new Dumper(); $this->path = __DIR__.'/Fixtures'; } protected function tearDown() { $this->parser = null; $this->dumper = null; $this->path = null; $this->array = null; } public function testIndentationInConstructor() { $dumper = new Dumper(7); $expected = <<<'EOF' '': bar foo: '#bar' 'foo''bar': { } bar: - 1 - foo foobar: foo: bar bar: - 1 - foo foobar: foo: bar bar: - 1 - foo EOF; $this->assertEquals($expected, $dumper->dump($this->array, 4, 0)); } /** * @group legacy */ public function testSetIndentation() { $this->dumper->setIndentation(7); $expected = <<<'EOF' '': bar foo: '#bar' 'foo''bar': { } bar: - 1 - foo foobar: foo: bar bar: - 1 - foo foobar: foo: bar bar: - 1 - foo EOF; $this->assertEquals($expected, $this->dumper->dump($this->array, 4, 0)); } public function testSpecifications() { $files = $this->parser->parse(file_get_contents($this->path.'/index.yml')); foreach ($files as $file) { $yamls = file_get_contents($this->path.'/'.$file.'.yml'); // split YAMLs documents foreach (preg_split('/^---( %YAML\:1\.0)?/m', $yamls) as $yaml) { if (!$yaml) { continue; } $test = $this->parser->parse($yaml); if (isset($test['dump_skip']) && $test['dump_skip']) { continue; } elseif (isset($test['todo']) && $test['todo']) { // TODO } else { eval('$expected = '.trim($test['php']).';'); $this->assertSame($expected, $this->parser->parse($this->dumper->dump($expected, 10)), $test['test']); } } } } public function testInlineLevel() { $expected = <<<'EOF' { '': bar, foo: '#bar', 'foo''bar': { }, bar: [1, foo], foobar: { foo: bar, bar: [1, foo], foobar: { foo: bar, bar: [1, foo] } } } EOF; $this->assertEquals($expected, $this->dumper->dump($this->array, -10), '->dump() takes an inline level argument'); $this->assertEquals($expected, $this->dumper->dump($this->array, 0), '->dump() takes an inline level argument'); $expected = <<<'EOF' '': bar foo: '#bar' 'foo''bar': { } bar: [1, foo] foobar: { foo: bar, bar: [1, foo], foobar: { foo: bar, bar: [1, foo] } } EOF; $this->assertEquals($expected, $this->dumper->dump($this->array, 1), '->dump() takes an inline level argument'); $expected = <<<'EOF' '': bar foo: '#bar' 'foo''bar': { } bar: - 1 - foo foobar: foo: bar bar: [1, foo] foobar: { foo: bar, bar: [1, foo] } EOF; $this->assertEquals($expected, $this->dumper->dump($this->array, 2), '->dump() takes an inline level argument'); $expected = <<<'EOF' '': bar foo: '#bar' 'foo''bar': { } bar: - 1 - foo foobar: foo: bar bar: - 1 - foo foobar: foo: bar bar: [1, foo] EOF; $this->assertEquals($expected, $this->dumper->dump($this->array, 3), '->dump() takes an inline level argument'); $expected = <<<'EOF' '': bar foo: '#bar' 'foo''bar': { } bar: - 1 - foo foobar: foo: bar bar: - 1 - foo foobar: foo: bar bar: - 1 - foo EOF; $this->assertEquals($expected, $this->dumper->dump($this->array, 4), '->dump() takes an inline level argument'); $this->assertEquals($expected, $this->dumper->dump($this->array, 10), '->dump() takes an inline level argument'); } public function testObjectSupportEnabled() { $dump = $this->dumper->dump(array('foo' => new A(), 'bar' => 1), 0, 0, Yaml::DUMP_OBJECT); $this->assertEquals('{ foo: !php/object:O:30:"Symfony\Component\Yaml\Tests\A":1:{s:1:"a";s:3:"foo";}, bar: 1 }', $dump, '->dump() is able to dump objects'); } /** * @group legacy */ public function testObjectSupportEnabledPassingTrue() { $dump = $this->dumper->dump(array('foo' => new A(), 'bar' => 1), 0, 0, false, true); $this->assertEquals('{ foo: !php/object:O:30:"Symfony\Component\Yaml\Tests\A":1:{s:1:"a";s:3:"foo";}, bar: 1 }', $dump, '->dump() is able to dump objects'); } public function testObjectSupportDisabledButNoExceptions() { $dump = $this->dumper->dump(array('foo' => new A(), 'bar' => 1)); $this->assertEquals('{ foo: null, bar: 1 }', $dump, '->dump() does not dump objects when disabled'); } /** * @expectedException \Symfony\Component\Yaml\Exception\DumpException */ public function testObjectSupportDisabledWithExceptions() { $this->dumper->dump(array('foo' => new A(), 'bar' => 1), 0, 0, Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE); } /** * @group legacy * @expectedException \Symfony\Component\Yaml\Exception\DumpException */ public function testObjectSupportDisabledWithExceptionsPassingTrue() { $this->dumper->dump(array('foo' => new A(), 'bar' => 1), 0, 0, true); } /** * @dataProvider getEscapeSequences */ public function testEscapedEscapeSequencesInQuotedScalar($input, $expected) { $this->assertEquals($expected, $this->dumper->dump($input)); } public function getEscapeSequences() { return array( 'empty string' => array('', "''"), 'null' => array("\x0", '"\\0"'), 'bell' => array("\x7", '"\\a"'), 'backspace' => array("\x8", '"\\b"'), 'horizontal-tab' => array("\t", '"\\t"'), 'line-feed' => array("\n", '"\\n"'), 'vertical-tab' => array("\v", '"\\v"'), 'form-feed' => array("\xC", '"\\f"'), 'carriage-return' => array("\r", '"\\r"'), 'escape' => array("\x1B", '"\\e"'), 'space' => array(' ', "' '"), 'double-quote' => array('"', "'\"'"), 'slash' => array('/', '/'), 'backslash' => array('\\', '\\'), 'next-line' => array("\xC2\x85", '"\\N"'), 'non-breaking-space' => array("\xc2\xa0", '"\\_"'), 'line-separator' => array("\xE2\x80\xA8", '"\\L"'), 'paragraph-separator' => array("\xE2\x80\xA9", '"\\P"'), 'colon' => array(':', "':'"), ); } public function testBinaryDataIsDumpedBase64Encoded() { $binaryData = file_get_contents(__DIR__.'/Fixtures/arrow.gif'); $expected = '{ data: !!binary '.base64_encode($binaryData).' }'; $this->assertSame($expected, $this->dumper->dump(array('data' => $binaryData))); } public function testNonUtf8DataIsDumpedBase64Encoded() { // "für" (ISO-8859-1 encoded) $this->assertSame('!!binary ZsM/cg==', $this->dumper->dump("f\xc3\x3fr")); } /** * @dataProvider objectAsMapProvider */ public function testDumpObjectAsMap($object, $expected) { $yaml = $this->dumper->dump($object, 0, 0, Yaml::DUMP_OBJECT_AS_MAP); $this->assertEquals($expected, Yaml::parse($yaml, Yaml::PARSE_OBJECT_FOR_MAP)); } public function objectAsMapProvider() { $tests = array(); $bar = new \stdClass(); $bar->class = 'classBar'; $bar->args = array('bar'); $zar = new \stdClass(); $foo = new \stdClass(); $foo->bar = $bar; $foo->zar = $zar; $object = new \stdClass(); $object->foo = $foo; $tests['stdClass'] = array($object, $object); $arrayObject = new \ArrayObject(); $arrayObject['foo'] = 'bar'; $arrayObject['baz'] = 'foobar'; $parsedArrayObject = new \stdClass(); $parsedArrayObject->foo = 'bar'; $parsedArrayObject->baz = 'foobar'; $tests['ArrayObject'] = array($arrayObject, $parsedArrayObject); $a = new A(); $tests['arbitrary-object'] = array($a, null); return $tests; } public function testDumpMultiLineStringAsScalarBlock() { $data = array( 'data' => array( 'single_line' => 'foo bar baz', 'multi_line' => "foo\nline with trailing spaces:\n \nbar\r\ninteger like line:\n123456789\nempty line:\n\nbaz", 'nested_inlined_multi_line_string' => array( 'inlined_multi_line' => "foo\nbar\r\nempty line:\n\nbaz", ), ), ); $this->assertSame(file_get_contents(__DIR__.'/Fixtures/multiple_lines_as_literal_block.yml'), $this->dumper->dump($data, 2, 0, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK)); } /** * @expectedException \InvalidArgumentException * @expectedExceptionMessage The indentation must be greater than zero */ public function testZeroIndentationThrowsException() { new Dumper(0); } /** * @expectedException \InvalidArgumentException * @expectedExceptionMessage The indentation must be greater than zero */ public function testNegativeIndentationThrowsException() { new Dumper(-4); } } class A { public $a = 'foo'; } symfony/yaml/Tests/YamlTest.php 0000604 00000002236 15247160545 0012577 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Yaml\Tests; use PHPUnit\Framework\TestCase; use Symfony\Component\Yaml\Yaml; class YamlTest extends TestCase { public function testParseAndDump() { $data = array('lorem' => 'ipsum', 'dolor' => 'sit'); $yml = Yaml::dump($data); $parsed = Yaml::parse($yml); $this->assertEquals($data, $parsed); } /** * @expectedException \InvalidArgumentException * @expectedExceptionMessage The indentation must be greater than zero */ public function testZeroIndentationThrowsException() { Yaml::dump(array('lorem' => 'ipsum', 'dolor' => 'sit'), 2, 0); } /** * @expectedException \InvalidArgumentException * @expectedExceptionMessage The indentation must be greater than zero */ public function testNegativeIndentationThrowsException() { Yaml::dump(array('lorem' => 'ipsum', 'dolor' => 'sit'), 2, -4); } } symfony/yaml/Tests/InlineTest.php 0000604 00000071002 15247160545 0013110 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Yaml\Tests; use PHPUnit\Framework\TestCase; use Symfony\Component\Yaml\Exception\ParseException; use Symfony\Component\Yaml\Inline; use Symfony\Component\Yaml\Yaml; class InlineTest extends TestCase { /** * @dataProvider getTestsForParse */ public function testParse($yaml, $value) { $this->assertSame($value, Inline::parse($yaml), sprintf('::parse() converts an inline YAML to a PHP structure (%s)', $yaml)); } /** * @dataProvider getTestsForParseWithMapObjects */ public function testParseWithMapObjects($yaml, $value) { $actual = Inline::parse($yaml, Yaml::PARSE_OBJECT_FOR_MAP); $this->assertSame(serialize($value), serialize($actual)); } /** * @dataProvider getTestsForParsePhpConstants */ public function testParsePhpConstants($yaml, $value) { $actual = Inline::parse($yaml, Yaml::PARSE_CONSTANT); $this->assertSame($value, $actual); } public function getTestsForParsePhpConstants() { return array( array('!php/const:Symfony\Component\Yaml\Yaml::PARSE_CONSTANT', Yaml::PARSE_CONSTANT), array('!php/const:PHP_INT_MAX', PHP_INT_MAX), array('[!php/const:PHP_INT_MAX]', array(PHP_INT_MAX)), array('{ foo: !php/const:PHP_INT_MAX }', array('foo' => PHP_INT_MAX)), ); } /** * @expectedException \Symfony\Component\Yaml\Exception\ParseException * @expectedExceptionMessage The constant "WRONG_CONSTANT" is not defined */ public function testParsePhpConstantThrowsExceptionWhenUndefined() { Inline::parse('!php/const:WRONG_CONSTANT', Yaml::PARSE_CONSTANT); } /** * @expectedException \Symfony\Component\Yaml\Exception\ParseException * @expectedExceptionMessageRegExp #The string "!php/const:PHP_INT_MAX" could not be parsed as a constant.*# */ public function testParsePhpConstantThrowsExceptionOnInvalidType() { Inline::parse('!php/const:PHP_INT_MAX', Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE); } /** * @group legacy * @dataProvider getTestsForParseWithMapObjects */ public function testParseWithMapObjectsPassingTrue($yaml, $value) { $actual = Inline::parse($yaml, false, false, true); $this->assertSame(serialize($value), serialize($actual)); } /** * @dataProvider getTestsForDump */ public function testDump($yaml, $value) { $this->assertEquals($yaml, Inline::dump($value), sprintf('::dump() converts a PHP structure to an inline YAML (%s)', $yaml)); $this->assertSame($value, Inline::parse(Inline::dump($value)), 'check consistency'); } public function testDumpNumericValueWithLocale() { $locale = setlocale(LC_NUMERIC, 0); if (false === $locale) { $this->markTestSkipped('Your platform does not support locales.'); } try { $requiredLocales = array('fr_FR.UTF-8', 'fr_FR.UTF8', 'fr_FR.utf-8', 'fr_FR.utf8', 'French_France.1252'); if (false === setlocale(LC_NUMERIC, $requiredLocales)) { $this->markTestSkipped('Could not set any of required locales: '.implode(', ', $requiredLocales)); } $this->assertEquals('1.2', Inline::dump(1.2)); $this->assertContains('fr', strtolower(setlocale(LC_NUMERIC, 0))); } finally { setlocale(LC_NUMERIC, $locale); } } public function testHashStringsResemblingExponentialNumericsShouldNotBeChangedToINF() { $value = '686e444'; $this->assertSame($value, Inline::parse(Inline::dump($value))); } /** * @expectedException \Symfony\Component\Yaml\Exception\ParseException * @expectedExceptionMessage Found unknown escape character "\V". */ public function testParseScalarWithNonEscapedBlackslashShouldThrowException() { Inline::parse('"Foo\Var"'); } /** * @expectedException \Symfony\Component\Yaml\Exception\ParseException */ public function testParseScalarWithNonEscapedBlackslashAtTheEndShouldThrowException() { Inline::parse('"Foo\\"'); } /** * @expectedException \Symfony\Component\Yaml\Exception\ParseException */ public function testParseScalarWithIncorrectlyQuotedStringShouldThrowException() { $value = "'don't do somthin' like that'"; Inline::parse($value); } /** * @expectedException \Symfony\Component\Yaml\Exception\ParseException */ public function testParseScalarWithIncorrectlyDoubleQuotedStringShouldThrowException() { $value = '"don"t do somthin" like that"'; Inline::parse($value); } /** * @expectedException \Symfony\Component\Yaml\Exception\ParseException */ public function testParseInvalidMappingKeyShouldThrowException() { $value = '{ "foo " bar": "bar" }'; Inline::parse($value); } /** * @group legacy * @expectedDeprecation Using a colon that is not followed by an indication character (i.e. " ", ",", "[", "]", "{", "}" is deprecated since version 3.2 and will throw a ParseException in 4.0. * throws \Symfony\Component\Yaml\Exception\ParseException in 4.0 */ public function testParseMappingKeyWithColonNotFollowedBySpace() { Inline::parse('{1:""}'); } /** * @expectedException \Symfony\Component\Yaml\Exception\ParseException */ public function testParseInvalidMappingShouldThrowException() { Inline::parse('[foo] bar'); } /** * @expectedException \Symfony\Component\Yaml\Exception\ParseException */ public function testParseInvalidSequenceShouldThrowException() { Inline::parse('{ foo: bar } bar'); } public function testParseScalarWithCorrectlyQuotedStringShouldReturnString() { $value = "'don''t do somthin'' like that'"; $expect = "don't do somthin' like that"; $this->assertSame($expect, Inline::parseScalar($value)); } /** * @dataProvider getDataForParseReferences */ public function testParseReferences($yaml, $expected) { $this->assertSame($expected, Inline::parse($yaml, 0, array('var' => 'var-value'))); } /** * @group legacy * @dataProvider getDataForParseReferences */ public function testParseReferencesAsFifthArgument($yaml, $expected) { $this->assertSame($expected, Inline::parse($yaml, false, false, false, array('var' => 'var-value'))); } public function getDataForParseReferences() { return array( 'scalar' => array('*var', 'var-value'), 'list' => array('[ *var ]', array('var-value')), 'list-in-list' => array('[[ *var ]]', array(array('var-value'))), 'map-in-list' => array('[ { key: *var } ]', array(array('key' => 'var-value'))), 'embedded-mapping-in-list' => array('[ key: *var ]', array(array('key' => 'var-value'))), 'map' => array('{ key: *var }', array('key' => 'var-value')), 'list-in-map' => array('{ key: [*var] }', array('key' => array('var-value'))), 'map-in-map' => array('{ foo: { bar: *var } }', array('foo' => array('bar' => 'var-value'))), ); } public function testParseMapReferenceInSequence() { $foo = array( 'a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', ); $this->assertSame(array($foo), Inline::parse('[*foo]', 0, array('foo' => $foo))); } /** * @group legacy */ public function testParseMapReferenceInSequenceAsFifthArgument() { $foo = array( 'a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', ); $this->assertSame(array($foo), Inline::parse('[*foo]', false, false, false, array('foo' => $foo))); } /** * @expectedException \Symfony\Component\Yaml\Exception\ParseException * @expectedExceptionMessage A reference must contain at least one character. */ public function testParseUnquotedAsterisk() { Inline::parse('{ foo: * }'); } /** * @expectedException \Symfony\Component\Yaml\Exception\ParseException * @expectedExceptionMessage A reference must contain at least one character. */ public function testParseUnquotedAsteriskFollowedByAComment() { Inline::parse('{ foo: * #foo }'); } /** * @dataProvider getReservedIndicators * @expectedException \Symfony\Component\Yaml\Exception\ParseException * @expectedExceptionMessage cannot start a plain scalar; you need to quote the scalar. */ public function testParseUnquotedScalarStartingWithReservedIndicator($indicator) { Inline::parse(sprintf('{ foo: %sfoo }', $indicator)); } public function getReservedIndicators() { return array(array('@'), array('`')); } /** * @dataProvider getScalarIndicators * @expectedException \Symfony\Component\Yaml\Exception\ParseException * @expectedExceptionMessage cannot start a plain scalar; you need to quote the scalar. */ public function testParseUnquotedScalarStartingWithScalarIndicator($indicator) { Inline::parse(sprintf('{ foo: %sfoo }', $indicator)); } public function getScalarIndicators() { return array(array('|'), array('>')); } /** * @group legacy * @expectedDeprecation Not quoting the scalar "%bar " starting with the "%" indicator character is deprecated since Symfony 3.1 and will throw a ParseException in 4.0. * throws \Symfony\Component\Yaml\Exception\ParseException in 4.0 */ public function testParseUnquotedScalarStartingWithPercentCharacter() { Inline::parse('{ foo: %bar }'); } /** * @dataProvider getDataForIsHash */ public function testIsHash($array, $expected) { $this->assertSame($expected, Inline::isHash($array)); } public function getDataForIsHash() { return array( array(array(), false), array(array(1, 2, 3), false), array(array(2 => 1, 1 => 2, 0 => 3), true), array(array('foo' => 1, 'bar' => 2), true), ); } public function getTestsForParse() { return array( array('', ''), array('null', null), array('false', false), array('true', true), array('12', 12), array('-12', -12), array('1_2', 12), array('_12', '_12'), array('12_', 12), array('"quoted string"', 'quoted string'), array("'quoted string'", 'quoted string'), array('12.30e+02', 12.30e+02), array('123.45_67', 123.4567), array('0x4D2', 0x4D2), array('0x_4_D_2_', 0x4D2), array('02333', 02333), array('0_2_3_3_3', 02333), array('.Inf', -log(0)), array('-.Inf', log(0)), array("'686e444'", '686e444'), array('686e444', 646e444), array('123456789123456789123456789123456789', '123456789123456789123456789123456789'), array('"foo\r\nbar"', "foo\r\nbar"), array("'foo#bar'", 'foo#bar'), array("'foo # bar'", 'foo # bar'), array("'#cfcfcf'", '#cfcfcf'), array('::form_base.html.twig', '::form_base.html.twig'), // Pre-YAML-1.2 booleans array("'y'", 'y'), array("'n'", 'n'), array("'yes'", 'yes'), array("'no'", 'no'), array("'on'", 'on'), array("'off'", 'off'), array('2007-10-30', gmmktime(0, 0, 0, 10, 30, 2007)), array('2007-10-30T02:59:43Z', gmmktime(2, 59, 43, 10, 30, 2007)), array('2007-10-30 02:59:43 Z', gmmktime(2, 59, 43, 10, 30, 2007)), array('1960-10-30 02:59:43 Z', gmmktime(2, 59, 43, 10, 30, 1960)), array('1730-10-30T02:59:43Z', gmmktime(2, 59, 43, 10, 30, 1730)), array('"a \\"string\\" with \'quoted strings inside\'"', 'a "string" with \'quoted strings inside\''), array("'a \"string\" with ''quoted strings inside'''", 'a "string" with \'quoted strings inside\''), // sequences // urls are no key value mapping. see #3609. Valid yaml "key: value" mappings require a space after the colon array('[foo, http://urls.are/no/mappings, false, null, 12]', array('foo', 'http://urls.are/no/mappings', false, null, 12)), array('[ foo , bar , false , null , 12 ]', array('foo', 'bar', false, null, 12)), array('[\'foo,bar\', \'foo bar\']', array('foo,bar', 'foo bar')), // mappings array('{foo: bar,bar: foo,false: false,null: null,integer: 12}', array('foo' => 'bar', 'bar' => 'foo', 'false' => false, 'null' => null, 'integer' => 12)), array('{ foo : bar, bar : foo, false : false, null : null, integer : 12 }', array('foo' => 'bar', 'bar' => 'foo', 'false' => false, 'null' => null, 'integer' => 12)), array('{foo: \'bar\', bar: \'foo: bar\'}', array('foo' => 'bar', 'bar' => 'foo: bar')), array('{\'foo\': \'bar\', "bar": \'foo: bar\'}', array('foo' => 'bar', 'bar' => 'foo: bar')), array('{\'foo\'\'\': \'bar\', "bar\"": \'foo: bar\'}', array('foo\'' => 'bar', 'bar"' => 'foo: bar')), array('{\'foo: \': \'bar\', "bar: ": \'foo: bar\'}', array('foo: ' => 'bar', 'bar: ' => 'foo: bar')), // nested sequences and mappings array('[foo, [bar, foo]]', array('foo', array('bar', 'foo'))), array('[foo, {bar: foo}]', array('foo', array('bar' => 'foo'))), array('{ foo: {bar: foo} }', array('foo' => array('bar' => 'foo'))), array('{ foo: [bar, foo] }', array('foo' => array('bar', 'foo'))), array('{ foo:{bar: foo} }', array('foo' => array('bar' => 'foo'))), array('{ foo:[bar, foo] }', array('foo' => array('bar', 'foo'))), array('[ foo, [ bar, foo ] ]', array('foo', array('bar', 'foo'))), array('[{ foo: {bar: foo} }]', array(array('foo' => array('bar' => 'foo')))), array('[foo, [bar, [foo, [bar, foo]], foo]]', array('foo', array('bar', array('foo', array('bar', 'foo')), 'foo'))), array('[foo, {bar: foo, foo: [foo, {bar: foo}]}, [foo, {bar: foo}]]', array('foo', array('bar' => 'foo', 'foo' => array('foo', array('bar' => 'foo'))), array('foo', array('bar' => 'foo')))), array('[foo, bar: { foo: bar }]', array('foo', '1' => array('bar' => array('foo' => 'bar')))), array('[foo, \'@foo.baz\', { \'%foo%\': \'foo is %foo%\', bar: \'%foo%\' }, true, \'@service_container\']', array('foo', '@foo.baz', array('%foo%' => 'foo is %foo%', 'bar' => '%foo%'), true, '@service_container')), ); } public function getTestsForParseWithMapObjects() { return array( array('', ''), array('null', null), array('false', false), array('true', true), array('12', 12), array('-12', -12), array('"quoted string"', 'quoted string'), array("'quoted string'", 'quoted string'), array('12.30e+02', 12.30e+02), array('0x4D2', 0x4D2), array('02333', 02333), array('.Inf', -log(0)), array('-.Inf', log(0)), array("'686e444'", '686e444'), array('686e444', 646e444), array('123456789123456789123456789123456789', '123456789123456789123456789123456789'), array('"foo\r\nbar"', "foo\r\nbar"), array("'foo#bar'", 'foo#bar'), array("'foo # bar'", 'foo # bar'), array("'#cfcfcf'", '#cfcfcf'), array('::form_base.html.twig', '::form_base.html.twig'), array('2007-10-30', gmmktime(0, 0, 0, 10, 30, 2007)), array('2007-10-30T02:59:43Z', gmmktime(2, 59, 43, 10, 30, 2007)), array('2007-10-30 02:59:43 Z', gmmktime(2, 59, 43, 10, 30, 2007)), array('1960-10-30 02:59:43 Z', gmmktime(2, 59, 43, 10, 30, 1960)), array('1730-10-30T02:59:43Z', gmmktime(2, 59, 43, 10, 30, 1730)), array('"a \\"string\\" with \'quoted strings inside\'"', 'a "string" with \'quoted strings inside\''), array("'a \"string\" with ''quoted strings inside'''", 'a "string" with \'quoted strings inside\''), // sequences // urls are no key value mapping. see #3609. Valid yaml "key: value" mappings require a space after the colon array('[foo, http://urls.are/no/mappings, false, null, 12]', array('foo', 'http://urls.are/no/mappings', false, null, 12)), array('[ foo , bar , false , null , 12 ]', array('foo', 'bar', false, null, 12)), array('[\'foo,bar\', \'foo bar\']', array('foo,bar', 'foo bar')), // mappings array('{foo: bar,bar: foo,false: false,null: null,integer: 12}', (object) array('foo' => 'bar', 'bar' => 'foo', 'false' => false, 'null' => null, 'integer' => 12)), array('{ foo : bar, bar : foo, false : false, null : null, integer : 12 }', (object) array('foo' => 'bar', 'bar' => 'foo', 'false' => false, 'null' => null, 'integer' => 12)), array('{foo: \'bar\', bar: \'foo: bar\'}', (object) array('foo' => 'bar', 'bar' => 'foo: bar')), array('{\'foo\': \'bar\', "bar": \'foo: bar\'}', (object) array('foo' => 'bar', 'bar' => 'foo: bar')), array('{\'foo\'\'\': \'bar\', "bar\"": \'foo: bar\'}', (object) array('foo\'' => 'bar', 'bar"' => 'foo: bar')), array('{\'foo: \': \'bar\', "bar: ": \'foo: bar\'}', (object) array('foo: ' => 'bar', 'bar: ' => 'foo: bar')), // nested sequences and mappings array('[foo, [bar, foo]]', array('foo', array('bar', 'foo'))), array('[foo, {bar: foo}]', array('foo', (object) array('bar' => 'foo'))), array('{ foo: {bar: foo} }', (object) array('foo' => (object) array('bar' => 'foo'))), array('{ foo: [bar, foo] }', (object) array('foo' => array('bar', 'foo'))), array('[ foo, [ bar, foo ] ]', array('foo', array('bar', 'foo'))), array('[{ foo: {bar: foo} }]', array((object) array('foo' => (object) array('bar' => 'foo')))), array('[foo, [bar, [foo, [bar, foo]], foo]]', array('foo', array('bar', array('foo', array('bar', 'foo')), 'foo'))), array('[foo, {bar: foo, foo: [foo, {bar: foo}]}, [foo, {bar: foo}]]', array('foo', (object) array('bar' => 'foo', 'foo' => array('foo', (object) array('bar' => 'foo'))), array('foo', (object) array('bar' => 'foo')))), array('[foo, bar: { foo: bar }]', array('foo', '1' => (object) array('bar' => (object) array('foo' => 'bar')))), array('[foo, \'@foo.baz\', { \'%foo%\': \'foo is %foo%\', bar: \'%foo%\' }, true, \'@service_container\']', array('foo', '@foo.baz', (object) array('%foo%' => 'foo is %foo%', 'bar' => '%foo%'), true, '@service_container')), array('{}', new \stdClass()), array('{ foo : bar, bar : {} }', (object) array('foo' => 'bar', 'bar' => new \stdClass())), array('{ foo : [], bar : {} }', (object) array('foo' => array(), 'bar' => new \stdClass())), array('{foo: \'bar\', bar: {} }', (object) array('foo' => 'bar', 'bar' => new \stdClass())), array('{\'foo\': \'bar\', "bar": {}}', (object) array('foo' => 'bar', 'bar' => new \stdClass())), array('{\'foo\': \'bar\', "bar": \'{}\'}', (object) array('foo' => 'bar', 'bar' => '{}')), array('[foo, [{}, {}]]', array('foo', array(new \stdClass(), new \stdClass()))), array('[foo, [[], {}]]', array('foo', array(array(), new \stdClass()))), array('[foo, [[{}, {}], {}]]', array('foo', array(array(new \stdClass(), new \stdClass()), new \stdClass()))), array('[foo, {bar: {}}]', array('foo', '1' => (object) array('bar' => new \stdClass()))), ); } public function getTestsForDump() { return array( array('null', null), array('false', false), array('true', true), array('12', 12), array("'1_2'", '1_2'), array('_12', '_12'), array("'12_'", '12_'), array("'quoted string'", 'quoted string'), array('!!float 1230', 12.30e+02), array('1234', 0x4D2), array('1243', 02333), array("'0x_4_D_2_'", '0x_4_D_2_'), array("'0_2_3_3_3'", '0_2_3_3_3'), array('.Inf', -log(0)), array('-.Inf', log(0)), array("'686e444'", '686e444'), array('"foo\r\nbar"', "foo\r\nbar"), array("'foo#bar'", 'foo#bar'), array("'foo # bar'", 'foo # bar'), array("'#cfcfcf'", '#cfcfcf'), array("'a \"string\" with ''quoted strings inside'''", 'a "string" with \'quoted strings inside\''), array("'-dash'", '-dash'), array("'-'", '-'), // Pre-YAML-1.2 booleans array("'y'", 'y'), array("'n'", 'n'), array("'yes'", 'yes'), array("'no'", 'no'), array("'on'", 'on'), array("'off'", 'off'), // sequences array('[foo, bar, false, null, 12]', array('foo', 'bar', false, null, 12)), array('[\'foo,bar\', \'foo bar\']', array('foo,bar', 'foo bar')), // mappings array('{ foo: bar, bar: foo, \'false\': false, \'null\': null, integer: 12 }', array('foo' => 'bar', 'bar' => 'foo', 'false' => false, 'null' => null, 'integer' => 12)), array('{ foo: bar, bar: \'foo: bar\' }', array('foo' => 'bar', 'bar' => 'foo: bar')), // nested sequences and mappings array('[foo, [bar, foo]]', array('foo', array('bar', 'foo'))), array('[foo, [bar, [foo, [bar, foo]], foo]]', array('foo', array('bar', array('foo', array('bar', 'foo')), 'foo'))), array('{ foo: { bar: foo } }', array('foo' => array('bar' => 'foo'))), array('[foo, { bar: foo }]', array('foo', array('bar' => 'foo'))), array('[foo, { bar: foo, foo: [foo, { bar: foo }] }, [foo, { bar: foo }]]', array('foo', array('bar' => 'foo', 'foo' => array('foo', array('bar' => 'foo'))), array('foo', array('bar' => 'foo')))), array('[foo, \'@foo.baz\', { \'%foo%\': \'foo is %foo%\', bar: \'%foo%\' }, true, \'@service_container\']', array('foo', '@foo.baz', array('%foo%' => 'foo is %foo%', 'bar' => '%foo%'), true, '@service_container')), array('{ foo: { bar: { 1: 2, baz: 3 } } }', array('foo' => array('bar' => array(1 => 2, 'baz' => 3)))), ); } /** * @dataProvider getTimestampTests */ public function testParseTimestampAsUnixTimestampByDefault($yaml, $year, $month, $day, $hour, $minute, $second) { $this->assertSame(gmmktime($hour, $minute, $second, $month, $day, $year), Inline::parse($yaml)); } /** * @dataProvider getTimestampTests */ public function testParseTimestampAsDateTimeObject($yaml, $year, $month, $day, $hour, $minute, $second, $timezone) { $expected = new \DateTime($yaml); $expected->setTimeZone(new \DateTimeZone('UTC')); $expected->setDate($year, $month, $day); if (PHP_VERSION_ID >= 70100) { $expected->setTime($hour, $minute, $second, 1000000 * ($second - (int) $second)); } else { $expected->setTime($hour, $minute, $second); } $date = Inline::parse($yaml, Yaml::PARSE_DATETIME); $this->assertEquals($expected, $date); $this->assertSame($timezone, $date->format('O')); } public function getTimestampTests() { return array( 'canonical' => array('2001-12-15T02:59:43.1Z', 2001, 12, 15, 2, 59, 43.1, '+0000'), 'ISO-8601' => array('2001-12-15t21:59:43.10-05:00', 2001, 12, 16, 2, 59, 43.1, '-0500'), 'spaced' => array('2001-12-15 21:59:43.10 -5', 2001, 12, 16, 2, 59, 43.1, '-0500'), 'date' => array('2001-12-15', 2001, 12, 15, 0, 0, 0, '+0000'), ); } /** * @dataProvider getTimestampTests */ public function testParseNestedTimestampListAsDateTimeObject($yaml, $year, $month, $day, $hour, $minute, $second) { $expected = new \DateTime($yaml); $expected->setTimeZone(new \DateTimeZone('UTC')); $expected->setDate($year, $month, $day); if (PHP_VERSION_ID >= 70100) { $expected->setTime($hour, $minute, $second, 1000000 * ($second - (int) $second)); } else { $expected->setTime($hour, $minute, $second); } $expectedNested = array('nested' => array($expected)); $yamlNested = "{nested: [$yaml]}"; $this->assertEquals($expectedNested, Inline::parse($yamlNested, Yaml::PARSE_DATETIME)); } /** * @dataProvider getDateTimeDumpTests */ public function testDumpDateTime($dateTime, $expected) { $this->assertSame($expected, Inline::dump($dateTime)); } public function getDateTimeDumpTests() { $tests = array(); $dateTime = new \DateTime('2001-12-15 21:59:43', new \DateTimeZone('UTC')); $tests['date-time-utc'] = array($dateTime, '2001-12-15T21:59:43+00:00'); $dateTime = new \DateTimeImmutable('2001-07-15 21:59:43', new \DateTimeZone('Europe/Berlin')); $tests['immutable-date-time-europe-berlin'] = array($dateTime, '2001-07-15T21:59:43+02:00'); return $tests; } /** * @dataProvider getBinaryData */ public function testParseBinaryData($data) { $this->assertSame('Hello world', Inline::parse($data)); } public function getBinaryData() { return array( 'enclosed with double quotes' => array('!!binary "SGVsbG8gd29ybGQ="'), 'enclosed with single quotes' => array("!!binary 'SGVsbG8gd29ybGQ='"), 'containing spaces' => array('!!binary "SGVs bG8gd 29ybGQ="'), ); } /** * @dataProvider getInvalidBinaryData * @expectedException \Symfony\Component\Yaml\Exception\ParseException */ public function testParseInvalidBinaryData($data, $expectedMessage) { if (method_exists($this, 'expectException')) { $this->expectExceptionMessageRegExp($expectedMessage); } else { $this->setExpectedExceptionRegExp(ParseException::class, $expectedMessage); } Inline::parse($data); } public function getInvalidBinaryData() { return array( 'length not a multiple of four' => array('!!binary "SGVsbG8d29ybGQ="', '/The normalized base64 encoded data \(data without whitespace characters\) length must be a multiple of four \(\d+ bytes given\)/'), 'invalid characters' => array('!!binary "SGVsbG8#d29ybGQ="', '/The base64 encoded data \(.*\) contains invalid characters/'), 'too many equals characters' => array('!!binary "SGVsbG8gd29yb==="', '/The base64 encoded data \(.*\) contains invalid characters/'), 'misplaced equals character' => array('!!binary "SGVsbG8gd29ybG=Q"', '/The base64 encoded data \(.*\) contains invalid characters/'), ); } /** * @expectedException \Symfony\Component\Yaml\Exception\ParseException * @expectedExceptionMessage Malformed inline YAML string: {this, is not, supported}. */ public function testNotSupportedMissingValue() { Inline::parse('{this, is not, supported}'); } public function testVeryLongQuotedStrings() { $longStringWithQuotes = str_repeat("x\r\n\\\"x\"x", 1000); $yamlString = Inline::dump(array('longStringWithQuotes' => $longStringWithQuotes)); $arrayFromYaml = Inline::parse($yamlString); $this->assertEquals($longStringWithQuotes, $arrayFromYaml['longStringWithQuotes']); } public function testOmittedMappingKeyIsParsedAsColon() { $this->assertSame(array(':' => 'foo'), Inline::parse('{: foo}')); } public function testBooleanMappingKeysAreConvertedToStrings() { $this->assertSame(array('false' => 'foo'), Inline::parse('{false: foo}')); $this->assertSame(array('true' => 'foo'), Inline::parse('{true: foo}')); } public function testTheEmptyStringIsAValidMappingKey() { $this->assertSame(array('' => 'foo'), Inline::parse('{ "": foo }')); } } symfony/yaml/Unescaper.php 0000604 00000007521 15247160545 0011662 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Yaml; use Symfony\Component\Yaml\Exception\ParseException; /** * Unescaper encapsulates unescaping rules for single and double-quoted * YAML strings. * * @author Matthew Lewinski <matthew@lewinski.org> * * @internal */ class Unescaper { /** * Regex fragment that matches an escaped character in a double quoted string. */ const REGEX_ESCAPED_CHARACTER = '\\\\(x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8}|.)'; /** * Unescapes a single quoted string. * * @param string $value A single quoted string * * @return string The unescaped string */ public function unescapeSingleQuotedString($value) { return str_replace('\'\'', '\'', $value); } /** * Unescapes a double quoted string. * * @param string $value A double quoted string * * @return string The unescaped string */ public function unescapeDoubleQuotedString($value) { $callback = function ($match) { return $this->unescapeCharacter($match[0]); }; // evaluate the string return preg_replace_callback('/'.self::REGEX_ESCAPED_CHARACTER.'/u', $callback, $value); } /** * Unescapes a character that was found in a double-quoted string. * * @param string $value An escaped character * * @return string The unescaped character */ private function unescapeCharacter($value) { switch ($value[1]) { case '0': return "\x0"; case 'a': return "\x7"; case 'b': return "\x8"; case 't': return "\t"; case "\t": return "\t"; case 'n': return "\n"; case 'v': return "\xB"; case 'f': return "\xC"; case 'r': return "\r"; case 'e': return "\x1B"; case ' ': return ' '; case '"': return '"'; case '/': return '/'; case '\\': return '\\'; case 'N': // U+0085 NEXT LINE return "\xC2\x85"; case '_': // U+00A0 NO-BREAK SPACE return "\xC2\xA0"; case 'L': // U+2028 LINE SEPARATOR return "\xE2\x80\xA8"; case 'P': // U+2029 PARAGRAPH SEPARATOR return "\xE2\x80\xA9"; case 'x': return self::utf8chr(hexdec(substr($value, 2, 2))); case 'u': return self::utf8chr(hexdec(substr($value, 2, 4))); case 'U': return self::utf8chr(hexdec(substr($value, 2, 8))); default: throw new ParseException(sprintf('Found unknown escape character "%s".', $value)); } } /** * Get the UTF-8 character for the given code point. * * @param int $c The unicode code point * * @return string The corresponding UTF-8 character */ private static function utf8chr($c) { if (0x80 > $c %= 0x200000) { return chr($c); } if (0x800 > $c) { return chr(0xC0 | $c >> 6).chr(0x80 | $c & 0x3F); } if (0x10000 > $c) { return chr(0xE0 | $c >> 12).chr(0x80 | $c >> 6 & 0x3F).chr(0x80 | $c & 0x3F); } return chr(0xF0 | $c >> 18).chr(0x80 | $c >> 12 & 0x3F).chr(0x80 | $c >> 6 & 0x3F).chr(0x80 | $c & 0x3F); } } symfony/yaml/phpunit.xml.dist 0000604 00000001405 15247160545 0012372 0 ustar 00 <?xml version="1.0" encoding="UTF-8"?> <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd" backupGlobals="false" colors="true" bootstrap="vendor/autoload.php" > <php> <ini name="error_reporting" value="-1" /> </php> <testsuites> <testsuite name="Symfony Yaml Component Test Suite"> <directory>./Tests/</directory> </testsuite> </testsuites> <filter> <whitelist> <directory>./</directory> <exclude> <directory>./Tests</directory> <directory>./vendor</directory> </exclude> </whitelist> </filter> </phpunit> symfony/yaml/Yaml.php 0000604 00000007664 15247160545 0010647 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Yaml; use Symfony\Component\Yaml\Exception\ParseException; /** * Yaml offers convenience methods to load and dump YAML. * * @author Fabien Potencier <fabien@symfony.com> */ class Yaml { const DUMP_OBJECT = 1; const PARSE_EXCEPTION_ON_INVALID_TYPE = 2; const PARSE_OBJECT = 4; const PARSE_OBJECT_FOR_MAP = 8; const DUMP_EXCEPTION_ON_INVALID_TYPE = 16; const PARSE_DATETIME = 32; const DUMP_OBJECT_AS_MAP = 64; const DUMP_MULTI_LINE_LITERAL_BLOCK = 128; const PARSE_CONSTANT = 256; /** * Parses YAML into a PHP value. * * Usage: * <code> * $array = Yaml::parse(file_get_contents('config.yml')); * print_r($array); * </code> * * @param string $input A string containing YAML * @param int $flags A bit field of PARSE_* constants to customize the YAML parser behavior * * @return mixed The YAML converted to a PHP value * * @throws ParseException If the YAML is not valid */ public static function parse($input, $flags = 0) { if (is_bool($flags)) { @trigger_error('Passing a boolean flag to toggle exception handling is deprecated since version 3.1 and will be removed in 4.0. Use the PARSE_EXCEPTION_ON_INVALID_TYPE flag instead.', E_USER_DEPRECATED); if ($flags) { $flags = self::PARSE_EXCEPTION_ON_INVALID_TYPE; } else { $flags = 0; } } if (func_num_args() >= 3) { @trigger_error('Passing a boolean flag to toggle object support is deprecated since version 3.1 and will be removed in 4.0. Use the PARSE_OBJECT flag instead.', E_USER_DEPRECATED); if (func_get_arg(2)) { $flags |= self::PARSE_OBJECT; } } if (func_num_args() >= 4) { @trigger_error('Passing a boolean flag to toggle object for map support is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::PARSE_OBJECT_FOR_MAP flag instead.', E_USER_DEPRECATED); if (func_get_arg(3)) { $flags |= self::PARSE_OBJECT_FOR_MAP; } } $yaml = new Parser(); return $yaml->parse($input, $flags); } /** * Dumps a PHP value to a YAML string. * * The dump method, when supplied with an array, will do its best * to convert the array into friendly YAML. * * @param mixed $input The PHP value * @param int $inline The level where you switch to inline YAML * @param int $indent The amount of spaces to use for indentation of nested nodes * @param int $flags A bit field of DUMP_* constants to customize the dumped YAML string * * @return string A YAML string representing the original PHP value */ public static function dump($input, $inline = 2, $indent = 4, $flags = 0) { if (is_bool($flags)) { @trigger_error('Passing a boolean flag to toggle exception handling is deprecated since version 3.1 and will be removed in 4.0. Use the DUMP_EXCEPTION_ON_INVALID_TYPE flag instead.', E_USER_DEPRECATED); if ($flags) { $flags = self::DUMP_EXCEPTION_ON_INVALID_TYPE; } else { $flags = 0; } } if (func_num_args() >= 5) { @trigger_error('Passing a boolean flag to toggle object support is deprecated since version 3.1 and will be removed in 4.0. Use the DUMP_OBJECT flag instead.', E_USER_DEPRECATED); if (func_get_arg(4)) { $flags |= self::DUMP_OBJECT; } } $yaml = new Dumper($indent); return $yaml->dump($input, $inline, 0, $flags); } } symfony/yaml/README.md 0000604 00000000717 15247160545 0010503 0 ustar 00 Yaml Component ============== The Yaml component loads and dumps YAML files. Resources --------- * [Documentation](https://symfony.com/doc/current/components/yaml/index.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) symfony/yaml/Inline.php 0000604 00000066777 15247160545 0011175 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Yaml; use Symfony\Component\Yaml\Exception\ParseException; use Symfony\Component\Yaml\Exception\DumpException; /** * Inline implements a YAML parser/dumper for the YAML inline syntax. * * @author Fabien Potencier <fabien@symfony.com> * * @internal */ class Inline { const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*+(?:\\\\.[^"\\\\]*+)*+)"|\'([^\']*+(?:\'\'[^\']*+)*+)\')'; public static $parsedLineNumber; private static $exceptionOnInvalidType = false; private static $objectSupport = false; private static $objectForMap = false; private static $constantSupport = false; /** * Converts a YAML string to a PHP value. * * @param string $value A YAML string * @param int $flags A bit field of PARSE_* constants to customize the YAML parser behavior * @param array $references Mapping of variable names to values * * @return mixed A PHP value * * @throws ParseException */ public static function parse($value, $flags = 0, $references = array()) { if (is_bool($flags)) { @trigger_error('Passing a boolean flag to toggle exception handling is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE flag instead.', E_USER_DEPRECATED); if ($flags) { $flags = Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE; } else { $flags = 0; } } if (func_num_args() >= 3 && !is_array($references)) { @trigger_error('Passing a boolean flag to toggle object support is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::PARSE_OBJECT flag instead.', E_USER_DEPRECATED); if ($references) { $flags |= Yaml::PARSE_OBJECT; } if (func_num_args() >= 4) { @trigger_error('Passing a boolean flag to toggle object for map support is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::PARSE_OBJECT_FOR_MAP flag instead.', E_USER_DEPRECATED); if (func_get_arg(3)) { $flags |= Yaml::PARSE_OBJECT_FOR_MAP; } } if (func_num_args() >= 5) { $references = func_get_arg(4); } else { $references = array(); } } self::$exceptionOnInvalidType = (bool) (Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE & $flags); self::$objectSupport = (bool) (Yaml::PARSE_OBJECT & $flags); self::$objectForMap = (bool) (Yaml::PARSE_OBJECT_FOR_MAP & $flags); self::$constantSupport = (bool) (Yaml::PARSE_CONSTANT & $flags); $value = trim($value); if ('' === $value) { return ''; } if (2 /* MB_OVERLOAD_STRING */ & (int) ini_get('mbstring.func_overload')) { $mbEncoding = mb_internal_encoding(); mb_internal_encoding('ASCII'); } $i = 0; switch ($value[0]) { case '[': $result = self::parseSequence($value, $flags, $i, $references); ++$i; break; case '{': $result = self::parseMapping($value, $flags, $i, $references); ++$i; break; default: $result = self::parseScalar($value, $flags, null, array('"', "'"), $i, true, $references); } // some comments are allowed at the end if (preg_replace('/\s+#.*$/A', '', substr($value, $i))) { throw new ParseException(sprintf('Unexpected characters near "%s".', substr($value, $i))); } if (isset($mbEncoding)) { mb_internal_encoding($mbEncoding); } return $result; } /** * Dumps a given PHP variable to a YAML string. * * @param mixed $value The PHP variable to convert * @param int $flags A bit field of Yaml::DUMP_* constants to customize the dumped YAML string * * @return string The YAML string representing the PHP value * * @throws DumpException When trying to dump PHP resource */ public static function dump($value, $flags = 0) { if (is_bool($flags)) { @trigger_error('Passing a boolean flag to toggle exception handling is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE flag instead.', E_USER_DEPRECATED); if ($flags) { $flags = Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE; } else { $flags = 0; } } if (func_num_args() >= 3) { @trigger_error('Passing a boolean flag to toggle object support is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::DUMP_OBJECT flag instead.', E_USER_DEPRECATED); if (func_get_arg(2)) { $flags |= Yaml::DUMP_OBJECT; } } switch (true) { case is_resource($value): if (Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE & $flags) { throw new DumpException(sprintf('Unable to dump PHP resources in a YAML file ("%s").', get_resource_type($value))); } return 'null'; case $value instanceof \DateTimeInterface: return $value->format('c'); case is_object($value): if (Yaml::DUMP_OBJECT & $flags) { return '!php/object:'.serialize($value); } if (Yaml::DUMP_OBJECT_AS_MAP & $flags && ($value instanceof \stdClass || $value instanceof \ArrayObject)) { return self::dumpArray((array) $value, $flags); } if (Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE & $flags) { throw new DumpException('Object support when dumping a YAML file has been disabled.'); } return 'null'; case is_array($value): return self::dumpArray($value, $flags); case null === $value: return 'null'; case true === $value: return 'true'; case false === $value: return 'false'; case ctype_digit($value): return is_string($value) ? "'$value'" : (int) $value; case is_numeric($value): $locale = setlocale(LC_NUMERIC, 0); if (false !== $locale) { setlocale(LC_NUMERIC, 'C'); } if (is_float($value)) { $repr = (string) $value; if (is_infinite($value)) { $repr = str_ireplace('INF', '.Inf', $repr); } elseif (floor($value) == $value && $repr == $value) { // Preserve float data type since storing a whole number will result in integer value. $repr = '!!float '.$repr; } } else { $repr = is_string($value) ? "'$value'" : (string) $value; } if (false !== $locale) { setlocale(LC_NUMERIC, $locale); } return $repr; case '' == $value: return "''"; case self::isBinaryString($value): return '!!binary '.base64_encode($value); case Escaper::requiresDoubleQuoting($value): return Escaper::escapeWithDoubleQuotes($value); case Escaper::requiresSingleQuoting($value): case preg_match('{^[0-9]+[_0-9]*$}', $value): case preg_match(self::getHexRegex(), $value): case preg_match(self::getTimestampRegex(), $value): return Escaper::escapeWithSingleQuotes($value); default: return $value; } } /** * Check if given array is hash or just normal indexed array. * * @internal * * @param array $value The PHP array to check * * @return bool true if value is hash array, false otherwise */ public static function isHash(array $value) { $expectedKey = 0; foreach ($value as $key => $val) { if ($key !== $expectedKey++) { return true; } } return false; } /** * Dumps a PHP array to a YAML string. * * @param array $value The PHP array to dump * @param int $flags A bit field of Yaml::DUMP_* constants to customize the dumped YAML string * * @return string The YAML string representing the PHP array */ private static function dumpArray($value, $flags) { // array if ($value && !self::isHash($value)) { $output = array(); foreach ($value as $val) { $output[] = self::dump($val, $flags); } return sprintf('[%s]', implode(', ', $output)); } // hash $output = array(); foreach ($value as $key => $val) { $output[] = sprintf('%s: %s', self::dump($key, $flags), self::dump($val, $flags)); } return sprintf('{ %s }', implode(', ', $output)); } /** * Parses a YAML scalar. * * @param string $scalar * @param int $flags * @param string $delimiters * @param array $stringDelimiters * @param int &$i * @param bool $evaluate * @param array $references * * @return string * * @throws ParseException When malformed inline YAML string is parsed * * @internal */ public static function parseScalar($scalar, $flags = 0, $delimiters = null, $stringDelimiters = array('"', "'"), &$i = 0, $evaluate = true, $references = array()) { if (in_array($scalar[$i], $stringDelimiters)) { // quoted scalar $output = self::parseQuotedScalar($scalar, $i); if (null !== $delimiters) { $tmp = ltrim(substr($scalar, $i), ' '); if (!in_array($tmp[0], $delimiters)) { throw new ParseException(sprintf('Unexpected characters (%s).', substr($scalar, $i))); } } } else { // "normal" string if (!$delimiters) { $output = substr($scalar, $i); $i += strlen($output); // remove comments if (preg_match('/[ \t]+#/', $output, $match, PREG_OFFSET_CAPTURE)) { $output = substr($output, 0, $match[0][1]); } } elseif (preg_match('/^(.+?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match)) { $output = $match[1]; $i += strlen($output); } else { throw new ParseException(sprintf('Malformed inline YAML string: %s.', $scalar)); } // a non-quoted string cannot start with @ or ` (reserved) nor with a scalar indicator (| or >) if ($output && ('@' === $output[0] || '`' === $output[0] || '|' === $output[0] || '>' === $output[0])) { throw new ParseException(sprintf('The reserved indicator "%s" cannot start a plain scalar; you need to quote the scalar.', $output[0])); } if ($output && '%' === $output[0]) { @trigger_error(sprintf('Not quoting the scalar "%s" starting with the "%%" indicator character is deprecated since Symfony 3.1 and will throw a ParseException in 4.0.', $output), E_USER_DEPRECATED); } if ($evaluate) { $output = self::evaluateScalar($output, $flags, $references); } } return $output; } /** * Parses a YAML quoted scalar. * * @param string $scalar * @param int &$i * * @return string * * @throws ParseException When malformed inline YAML string is parsed */ private static function parseQuotedScalar($scalar, &$i) { if (!preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match)) { throw new ParseException(sprintf('Malformed inline YAML string: %s.', substr($scalar, $i))); } $output = substr($match[0], 1, strlen($match[0]) - 2); $unescaper = new Unescaper(); if ('"' == $scalar[$i]) { $output = $unescaper->unescapeDoubleQuotedString($output); } else { $output = $unescaper->unescapeSingleQuotedString($output); } $i += strlen($match[0]); return $output; } /** * Parses a YAML sequence. * * @param string $sequence * @param int $flags * @param int &$i * @param array $references * * @return array * * @throws ParseException When malformed inline YAML string is parsed */ private static function parseSequence($sequence, $flags, &$i = 0, $references = array()) { $output = array(); $len = strlen($sequence); ++$i; // [foo, bar, ...] while ($i < $len) { switch ($sequence[$i]) { case '[': // nested sequence $output[] = self::parseSequence($sequence, $flags, $i, $references); break; case '{': // nested mapping $output[] = self::parseMapping($sequence, $flags, $i, $references); break; case ']': return $output; case ',': case ' ': break; default: $isQuoted = in_array($sequence[$i], array('"', "'")); $value = self::parseScalar($sequence, $flags, array(',', ']'), array('"', "'"), $i, true, $references); // the value can be an array if a reference has been resolved to an array var if (is_string($value) && !$isQuoted && false !== strpos($value, ': ')) { // embedded mapping? try { $pos = 0; $value = self::parseMapping('{'.$value.'}', $flags, $pos, $references); } catch (\InvalidArgumentException $e) { // no, it's not } } $output[] = $value; --$i; } ++$i; } throw new ParseException(sprintf('Malformed inline YAML string: %s.', $sequence)); } /** * Parses a YAML mapping. * * @param string $mapping * @param int $flags * @param int &$i * @param array $references * * @return array|\stdClass * * @throws ParseException When malformed inline YAML string is parsed */ private static function parseMapping($mapping, $flags, &$i = 0, $references = array()) { $output = array(); $len = strlen($mapping); ++$i; // {foo: bar, bar:foo, ...} while ($i < $len) { switch ($mapping[$i]) { case ' ': case ',': ++$i; continue 2; case '}': if (self::$objectForMap) { return (object) $output; } return $output; } // key $key = self::parseScalar($mapping, $flags, array(':', ' '), array('"', "'"), $i, false); if (':' !== $key && false === $i = strpos($mapping, ':', $i)) { break; } if (':' !== $key && (!isset($mapping[$i + 1]) || !in_array($mapping[$i + 1], array(' ', ',', '[', ']', '{', '}'), true))) { @trigger_error('Using a colon that is not followed by an indication character (i.e. " ", ",", "[", "]", "{", "}" is deprecated since version 3.2 and will throw a ParseException in 4.0.', E_USER_DEPRECATED); } // value $done = false; while ($i < $len) { switch ($mapping[$i]) { case '[': // nested sequence $value = self::parseSequence($mapping, $flags, $i, $references); // Spec: Keys MUST be unique; first one wins. // Parser cannot abort this mapping earlier, since lines // are processed sequentially. if (!isset($output[$key])) { $output[$key] = $value; } else { @trigger_error(sprintf('Duplicate key "%s" detected on line %d whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key, self::$parsedLineNumber + 1), E_USER_DEPRECATED); } $done = true; break; case '{': // nested mapping $value = self::parseMapping($mapping, $flags, $i, $references); // Spec: Keys MUST be unique; first one wins. // Parser cannot abort this mapping earlier, since lines // are processed sequentially. if (!isset($output[$key])) { $output[$key] = $value; } else { @trigger_error(sprintf('Duplicate key "%s" detected on line %d whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key, self::$parsedLineNumber + 1), E_USER_DEPRECATED); } $done = true; break; case ':': case ' ': break; default: $value = self::parseScalar($mapping, $flags, array(',', '}'), array('"', "'"), $i, true, $references); // Spec: Keys MUST be unique; first one wins. // Parser cannot abort this mapping earlier, since lines // are processed sequentially. if (!isset($output[$key])) { $output[$key] = $value; } else { @trigger_error(sprintf('Duplicate key "%s" detected on line %d whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key, self::$parsedLineNumber + 1), E_USER_DEPRECATED); } $done = true; --$i; } ++$i; if ($done) { continue 2; } } } throw new ParseException(sprintf('Malformed inline YAML string: %s.', $mapping)); } /** * Evaluates scalars and replaces magic values. * * @param string $scalar * @param int $flags * @param array $references * * @return string A YAML string * * @throws ParseException when object parsing support was disabled and the parser detected a PHP object or when a reference could not be resolved */ private static function evaluateScalar($scalar, $flags, $references = array()) { $scalar = trim($scalar); $scalarLower = strtolower($scalar); if (0 === strpos($scalar, '*')) { if (false !== $pos = strpos($scalar, '#')) { $value = substr($scalar, 1, $pos - 2); } else { $value = substr($scalar, 1); } // an unquoted * if (false === $value || '' === $value) { throw new ParseException('A reference must contain at least one character.'); } if (!array_key_exists($value, $references)) { throw new ParseException(sprintf('Reference "%s" does not exist.', $value)); } return $references[$value]; } switch (true) { case 'null' === $scalarLower: case '' === $scalar: case '~' === $scalar: return; case 'true' === $scalarLower: return true; case 'false' === $scalarLower: return false; // Optimise for returning strings. case $scalar[0] === '+' || $scalar[0] === '-' || $scalar[0] === '.' || $scalar[0] === '!' || is_numeric($scalar[0]): switch (true) { case 0 === strpos($scalar, '!str'): return (string) substr($scalar, 5); case 0 === strpos($scalar, '! '): return (int) self::parseScalar(substr($scalar, 2), $flags); case 0 === strpos($scalar, '!php/object:'): if (self::$objectSupport) { return unserialize(substr($scalar, 12)); } if (self::$exceptionOnInvalidType) { throw new ParseException('Object support when parsing a YAML file has been disabled.'); } return; case 0 === strpos($scalar, '!!php/object:'): if (self::$objectSupport) { @trigger_error('The !!php/object tag to indicate dumped PHP objects is deprecated since version 3.1 and will be removed in 4.0. Use the !php/object tag instead.', E_USER_DEPRECATED); return unserialize(substr($scalar, 13)); } if (self::$exceptionOnInvalidType) { throw new ParseException('Object support when parsing a YAML file has been disabled.'); } return; case 0 === strpos($scalar, '!php/const:'): if (self::$constantSupport) { if (defined($const = substr($scalar, 11))) { return constant($const); } throw new ParseException(sprintf('The constant "%s" is not defined.', $const)); } if (self::$exceptionOnInvalidType) { throw new ParseException(sprintf('The string "%s" could not be parsed as a constant. Have you forgotten to pass the "Yaml::PARSE_CONSTANT" flag to the parser?', $scalar)); } return; case 0 === strpos($scalar, '!!float '): return (float) substr($scalar, 8); case preg_match('{^[+-]?[0-9][0-9_]*$}', $scalar): $scalar = str_replace('_', '', (string) $scalar); // omitting the break / return as integers are handled in the next case case ctype_digit($scalar): $raw = $scalar; $cast = (int) $scalar; return '0' == $scalar[0] ? octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw); case '-' === $scalar[0] && ctype_digit(substr($scalar, 1)): $raw = $scalar; $cast = (int) $scalar; return '0' == $scalar[1] ? octdec($scalar) : (((string) $raw === (string) $cast) ? $cast : $raw); case is_numeric($scalar): case preg_match(self::getHexRegex(), $scalar): $scalar = str_replace('_', '', $scalar); return '0x' === $scalar[0].$scalar[1] ? hexdec($scalar) : (float) $scalar; case '.inf' === $scalarLower: case '.nan' === $scalarLower: return -log(0); case '-.inf' === $scalarLower: return log(0); case 0 === strpos($scalar, '!!binary '): return self::evaluateBinaryScalar(substr($scalar, 9)); case preg_match('/^(-|\+)?[0-9][0-9,]*(\.[0-9_]+)?$/', $scalar): case preg_match('/^(-|\+)?[0-9][0-9_]*(\.[0-9_]+)?$/', $scalar): if (false !== strpos($scalar, ',')) { @trigger_error('Using the comma as a group separator for floats is deprecated since version 3.2 and will be removed in 4.0.', E_USER_DEPRECATED); } return (float) str_replace(array(',', '_'), '', $scalar); case preg_match(self::getTimestampRegex(), $scalar): if (Yaml::PARSE_DATETIME & $flags) { // When no timezone is provided in the parsed date, YAML spec says we must assume UTC. return new \DateTime($scalar, new \DateTimeZone('UTC')); } $timeZone = date_default_timezone_get(); date_default_timezone_set('UTC'); $time = strtotime($scalar); date_default_timezone_set($timeZone); return $time; } default: return (string) $scalar; } } /** * @param string $scalar * * @return string * * @internal */ public static function evaluateBinaryScalar($scalar) { $parsedBinaryData = self::parseScalar(preg_replace('/\s/', '', $scalar)); if (0 !== (strlen($parsedBinaryData) % 4)) { throw new ParseException(sprintf('The normalized base64 encoded data (data without whitespace characters) length must be a multiple of four (%d bytes given).', strlen($parsedBinaryData))); } if (!preg_match('#^[A-Z0-9+/]+={0,2}$#i', $parsedBinaryData)) { throw new ParseException(sprintf('The base64 encoded data (%s) contains invalid characters.', $parsedBinaryData)); } return base64_decode($parsedBinaryData, true); } private static function isBinaryString($value) { return !preg_match('//u', $value) || preg_match('/[^\x00\x07-\x0d\x1B\x20-\xff]/', $value); } /** * Gets a regex that matches a YAML date. * * @return string The regular expression * * @see http://www.yaml.org/spec/1.2/spec.html#id2761573 */ private static function getTimestampRegex() { return <<<EOF ~^ (?P<year>[0-9][0-9][0-9][0-9]) -(?P<month>[0-9][0-9]?) -(?P<day>[0-9][0-9]?) (?:(?:[Tt]|[ \t]+) (?P<hour>[0-9][0-9]?) :(?P<minute>[0-9][0-9]) :(?P<second>[0-9][0-9]) (?:\.(?P<fraction>[0-9]*))? (?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?) (?::(?P<tz_minute>[0-9][0-9]))?))?)? $~x EOF; } /** * Gets a regex that matches a YAML number in hexadecimal notation. * * @return string */ private static function getHexRegex() { return '~^0x[0-9a-f_]++$~i'; } } symfony/yaml/CHANGELOG.md 0000604 00000004244 15247160545 0011034 0 ustar 00 CHANGELOG ========= 3.2.0 ----- * Mappings with a colon (`:`) that is not followed by a whitespace are deprecated and will lead to a `ParseException` in Symfony 4.0 (e.g. `foo:bar` must be `foo: bar`). * Added support for parsing PHP constants: ```php Yaml::parse('!php/const:PHP_INT_MAX', Yaml::PARSE_CONSTANT); ``` * Support for silently ignoring duplicate mapping keys in YAML has been deprecated and will lead to a `ParseException` in Symfony 4.0. 3.1.0 ----- * Strings that are not UTF-8 encoded will be dumped as base64 encoded binary data. * Added support for dumping multi line strings as literal blocks. * Added support for parsing base64 encoded binary data when they are tagged with the `!!binary` tag. * Added support for parsing timestamps as `\DateTime` objects: ```php Yaml::parse('2001-12-15 21:59:43.10 -5', Yaml::PARSE_DATETIME); ``` * `\DateTime` and `\DateTimeImmutable` objects are dumped as YAML timestamps. * Deprecated usage of `%` at the beginning of an unquoted string. * Added support for customizing the YAML parser behavior through an optional bit field: ```php Yaml::parse('{ "foo": "bar", "fiz": "cat" }', Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE | Yaml::PARSE_OBJECT | Yaml::PARSE_OBJECT_FOR_MAP); ``` * Added support for customizing the dumped YAML string through an optional bit field: ```php Yaml::dump(array('foo' => new A(), 'bar' => 1), 0, 0, Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE | Yaml::DUMP_OBJECT); ``` 3.0.0 ----- * Yaml::parse() now throws an exception when a blackslash is not escaped in double-quoted strings 2.8.0 ----- * Deprecated usage of a colon in an unquoted mapping value * Deprecated usage of @, \`, | and > at the beginning of an unquoted string * When surrounding strings with double-quotes, you must now escape `\` characters. Not escaping those characters (when surrounded by double-quotes) is deprecated. Before: ```yml class: "Foo\Var" ``` After: ```yml class: "Foo\\Var" ``` 2.1.0 ----- * Yaml::parse() does not evaluate loaded files as PHP files by default anymore (call Yaml::enablePhpParsing() to get back the old behavior) symfony/yaml/Dumper.php 0000604 00000007343 15247160545 0011173 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Yaml; /** * Dumper dumps PHP variables to YAML strings. * * @author Fabien Potencier <fabien@symfony.com> */ class Dumper { /** * The amount of spaces to use for indentation of nested nodes. * * @var int */ protected $indentation; /** * @param int $indentation */ public function __construct($indentation = 4) { if ($indentation < 1) { throw new \InvalidArgumentException('The indentation must be greater than zero.'); } $this->indentation = $indentation; } /** * Sets the indentation. * * @param int $num The amount of spaces to use for indentation of nested nodes */ public function setIndentation($num) { @trigger_error('The '.__METHOD__.' method is deprecated since version 3.1 and will be removed in 4.0. Pass the indentation to the constructor instead.', E_USER_DEPRECATED); $this->indentation = (int) $num; } /** * Dumps a PHP value to YAML. * * @param mixed $input The PHP value * @param int $inline The level where you switch to inline YAML * @param int $indent The level of indentation (used internally) * @param int $flags A bit field of Yaml::DUMP_* constants to customize the dumped YAML string * * @return string The YAML representation of the PHP value */ public function dump($input, $inline = 0, $indent = 0, $flags = 0) { if (is_bool($flags)) { @trigger_error('Passing a boolean flag to toggle exception handling is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE flag instead.', E_USER_DEPRECATED); if ($flags) { $flags = Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE; } else { $flags = 0; } } if (func_num_args() >= 5) { @trigger_error('Passing a boolean flag to toggle object support is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::DUMP_OBJECT flag instead.', E_USER_DEPRECATED); if (func_get_arg(4)) { $flags |= Yaml::DUMP_OBJECT; } } $output = ''; $prefix = $indent ? str_repeat(' ', $indent) : ''; if ($inline <= 0 || !is_array($input) || empty($input)) { $output .= $prefix.Inline::dump($input, $flags); } else { $isAHash = Inline::isHash($input); foreach ($input as $key => $value) { if ($inline >= 1 && Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK & $flags && is_string($value) && false !== strpos($value, "\n")) { $output .= sprintf("%s%s%s |\n", $prefix, $isAHash ? Inline::dump($key, $flags).':' : '-', ''); foreach (preg_split('/\n|\r\n/', $value) as $row) { $output .= sprintf("%s%s%s\n", $prefix, str_repeat(' ', $this->indentation), $row); } continue; } $willBeInlined = $inline - 1 <= 0 || !is_array($value) || empty($value); $output .= sprintf('%s%s%s%s', $prefix, $isAHash ? Inline::dump($key, $flags).':' : '-', $willBeInlined ? ' ' : "\n", $this->dump($value, $inline - 1, $willBeInlined ? 0 : $indent + $this->indentation, $flags) ).($willBeInlined ? "\n" : ''); } } return $output; } } symfony/yaml/Exception/ParseException.php 0000604 00000006535 15247160545 0014630 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Yaml\Exception; /** * Exception class thrown when an error occurs during parsing. * * @author Fabien Potencier <fabien@symfony.com> */ class ParseException extends RuntimeException { private $parsedFile; private $parsedLine; private $snippet; private $rawMessage; /** * Constructor. * * @param string $message The error message * @param int $parsedLine The line where the error occurred * @param int $snippet The snippet of code near the problem * @param string $parsedFile The file name where the error occurred * @param \Exception $previous The previous exception */ public function __construct($message, $parsedLine = -1, $snippet = null, $parsedFile = null, \Exception $previous = null) { $this->parsedFile = $parsedFile; $this->parsedLine = $parsedLine; $this->snippet = $snippet; $this->rawMessage = $message; $this->updateRepr(); parent::__construct($this->message, 0, $previous); } /** * Gets the snippet of code near the error. * * @return string The snippet of code */ public function getSnippet() { return $this->snippet; } /** * Sets the snippet of code near the error. * * @param string $snippet The code snippet */ public function setSnippet($snippet) { $this->snippet = $snippet; $this->updateRepr(); } /** * Gets the filename where the error occurred. * * This method returns null if a string is parsed. * * @return string The filename */ public function getParsedFile() { return $this->parsedFile; } /** * Sets the filename where the error occurred. * * @param string $parsedFile The filename */ public function setParsedFile($parsedFile) { $this->parsedFile = $parsedFile; $this->updateRepr(); } /** * Gets the line where the error occurred. * * @return int The file line */ public function getParsedLine() { return $this->parsedLine; } /** * Sets the line where the error occurred. * * @param int $parsedLine The file line */ public function setParsedLine($parsedLine) { $this->parsedLine = $parsedLine; $this->updateRepr(); } private function updateRepr() { $this->message = $this->rawMessage; $dot = false; if ('.' === substr($this->message, -1)) { $this->message = substr($this->message, 0, -1); $dot = true; } if (null !== $this->parsedFile) { $this->message .= sprintf(' in %s', json_encode($this->parsedFile, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); } if ($this->parsedLine >= 0) { $this->message .= sprintf(' at line %d', $this->parsedLine); } if ($this->snippet) { $this->message .= sprintf(' (near "%s")', $this->snippet); } if ($dot) { $this->message .= '.'; } } } symfony/yaml/Exception/RuntimeException.php 0000604 00000000745 15247160545 0015176 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Yaml\Exception; /** * Exception class thrown when an error occurs during parsing. * * @author Romain Neutron <imprec@gmail.com> */ class RuntimeException extends \RuntimeException implements ExceptionInterface { } symfony/yaml/Exception/DumpException.php 0000604 00000000707 15247160545 0014456 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Yaml\Exception; /** * Exception class thrown when an error occurs during dumping. * * @author Fabien Potencier <fabien@symfony.com> */ class DumpException extends RuntimeException { } symfony/yaml/Exception/ExceptionInterface.php 0000604 00000000673 15247160545 0015453 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Yaml\Exception; /** * Exception interface for all exceptions thrown by the component. * * @author Fabien Potencier <fabien@symfony.com> */ interface ExceptionInterface { } symfony/yaml/.gitignore 0000604 00000000042 15247160545 0011203 0 ustar 00 vendor/ composer.lock phpunit.xml symfony/yaml/Parser.php 0000604 00000102376 15247160545 0011175 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Yaml; use Symfony\Component\Yaml\Exception\ParseException; /** * Parser parses YAML strings to convert them to PHP arrays. * * @author Fabien Potencier <fabien@symfony.com> */ class Parser { const TAG_PATTERN = '((?P<tag>![\w!.\/:-]+) +)?'; const BLOCK_SCALAR_HEADER_PATTERN = '(?P<separator>\||>)(?P<modifiers>\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P<comments> +#.*)?'; private $offset = 0; private $totalNumberOfLines; private $lines = array(); private $currentLineNb = -1; private $currentLine = ''; private $refs = array(); private $skippedLineNumbers = array(); private $locallySkippedLineNumbers = array(); /** * Constructor. * * @param int $offset The offset of YAML document (used for line numbers in error messages) * @param int|null $totalNumberOfLines The overall number of lines being parsed * @param int[] $skippedLineNumbers Number of comment lines that have been skipped by the parser */ public function __construct($offset = 0, $totalNumberOfLines = null, array $skippedLineNumbers = array()) { $this->offset = $offset; $this->totalNumberOfLines = $totalNumberOfLines; $this->skippedLineNumbers = $skippedLineNumbers; } /** * Parses a YAML string to a PHP value. * * @param string $value A YAML string * @param int $flags A bit field of PARSE_* constants to customize the YAML parser behavior * * @return mixed A PHP value * * @throws ParseException If the YAML is not valid */ public function parse($value, $flags = 0) { if (is_bool($flags)) { @trigger_error('Passing a boolean flag to toggle exception handling is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE flag instead.', E_USER_DEPRECATED); if ($flags) { $flags = Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE; } else { $flags = 0; } } if (func_num_args() >= 3) { @trigger_error('Passing a boolean flag to toggle object support is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::PARSE_OBJECT flag instead.', E_USER_DEPRECATED); if (func_get_arg(2)) { $flags |= Yaml::PARSE_OBJECT; } } if (func_num_args() >= 4) { @trigger_error('Passing a boolean flag to toggle object for map support is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::PARSE_OBJECT_FOR_MAP flag instead.', E_USER_DEPRECATED); if (func_get_arg(3)) { $flags |= Yaml::PARSE_OBJECT_FOR_MAP; } } if (!preg_match('//u', $value)) { throw new ParseException('The YAML value does not appear to be valid UTF-8.'); } $this->currentLineNb = -1; $this->currentLine = ''; $value = $this->cleanup($value); $this->lines = explode("\n", $value); if (null === $this->totalNumberOfLines) { $this->totalNumberOfLines = count($this->lines); } if (2 /* MB_OVERLOAD_STRING */ & (int) ini_get('mbstring.func_overload')) { $mbEncoding = mb_internal_encoding(); mb_internal_encoding('UTF-8'); } $data = array(); $context = null; $allowOverwrite = false; while ($this->moveToNextLine()) { if ($this->isCurrentLineEmpty()) { continue; } // tab? if ("\t" === $this->currentLine[0]) { throw new ParseException('A YAML file cannot contain tabs as indentation.', $this->getRealCurrentLineNb() + 1, $this->currentLine); } $isRef = $mergeNode = false; if (preg_match('#^\-((?P<leadspaces>\s+)(?P<value>.+?))?\s*$#u', $this->currentLine, $values)) { if ($context && 'mapping' == $context) { throw new ParseException('You cannot define a sequence item when in a mapping', $this->getRealCurrentLineNb() + 1, $this->currentLine); } $context = 'sequence'; if (isset($values['value']) && preg_match('#^&(?P<ref>[^ ]+) *(?P<value>.*)#u', $values['value'], $matches)) { $isRef = $matches['ref']; $values['value'] = $matches['value']; } // array if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#')) { $data[] = $this->parseBlock($this->getRealCurrentLineNb() + 1, $this->getNextEmbedBlock(null, true), $flags); } else { if (isset($values['leadspaces']) && preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\{\[].*?) *\:(\s+(?P<value>.+?))?\s*$#u', $values['value'], $matches) ) { // this is a compact notation element, add to next block and parse $block = $values['value']; if ($this->isNextLineIndented()) { $block .= "\n".$this->getNextEmbedBlock($this->getCurrentLineIndentation() + strlen($values['leadspaces']) + 1); } $data[] = $this->parseBlock($this->getRealCurrentLineNb(), $block, $flags); } else { $data[] = $this->parseValue($values['value'], $flags, $context); } } if ($isRef) { $this->refs[$isRef] = end($data); } } elseif (preg_match('#^(?P<key>'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\[\{].*?) *\:(\s+(?P<value>.+?))?\s*$#u', $this->currentLine, $values) && (false === strpos($values['key'], ' #') || in_array($values['key'][0], array('"', "'")))) { if ($context && 'sequence' == $context) { throw new ParseException('You cannot define a mapping item when in a sequence', $this->currentLineNb + 1, $this->currentLine); } $context = 'mapping'; // force correct settings Inline::parse(null, $flags, $this->refs); try { Inline::$parsedLineNumber = $this->getRealCurrentLineNb(); $key = Inline::parseScalar($values['key']); } catch (ParseException $e) { $e->setParsedLine($this->getRealCurrentLineNb() + 1); $e->setSnippet($this->currentLine); throw $e; } // Convert float keys to strings, to avoid being converted to integers by PHP if (is_float($key)) { $key = (string) $key; } if ('<<' === $key) { $mergeNode = true; $allowOverwrite = true; if (isset($values['value']) && 0 === strpos($values['value'], '*')) { $refName = substr($values['value'], 1); if (!array_key_exists($refName, $this->refs)) { throw new ParseException(sprintf('Reference "%s" does not exist.', $refName), $this->getRealCurrentLineNb() + 1, $this->currentLine); } $refValue = $this->refs[$refName]; if (!is_array($refValue)) { throw new ParseException('YAML merge keys used with a scalar value instead of an array.', $this->getRealCurrentLineNb() + 1, $this->currentLine); } $data += $refValue; // array union } else { if (isset($values['value']) && $values['value'] !== '') { $value = $values['value']; } else { $value = $this->getNextEmbedBlock(); } $parsed = $this->parseBlock($this->getRealCurrentLineNb() + 1, $value, $flags); if (!is_array($parsed)) { throw new ParseException('YAML merge keys used with a scalar value instead of an array.', $this->getRealCurrentLineNb() + 1, $this->currentLine); } if (isset($parsed[0])) { // If the value associated with the merge key is a sequence, then this sequence is expected to contain mapping nodes // and each of these nodes is merged in turn according to its order in the sequence. Keys in mapping nodes earlier // in the sequence override keys specified in later mapping nodes. foreach ($parsed as $parsedItem) { if (!is_array($parsedItem)) { throw new ParseException('Merge items must be arrays.', $this->getRealCurrentLineNb() + 1, $parsedItem); } $data += $parsedItem; // array union } } else { // If the value associated with the key is a single mapping node, each of its key/value pairs is inserted into the // current mapping, unless the key already exists in it. $data += $parsed; // array union } } } elseif (isset($values['value']) && preg_match('#^&(?P<ref>[^ ]+) *(?P<value>.*)#u', $values['value'], $matches)) { $isRef = $matches['ref']; $values['value'] = $matches['value']; } if ($mergeNode) { // Merge keys } elseif (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#')) { // hash // if next line is less indented or equal, then it means that the current value is null if (!$this->isNextLineIndented() && !$this->isNextLineUnIndentedCollection()) { // Spec: Keys MUST be unique; first one wins. // But overwriting is allowed when a merge node is used in current block. if ($allowOverwrite || !isset($data[$key])) { $data[$key] = null; } else { @trigger_error(sprintf('Duplicate key "%s" detected on line %d whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key, $this->getRealCurrentLineNb() + 1), E_USER_DEPRECATED); } } else { // remember the parsed line number here in case we need it to provide some contexts in error messages below $realCurrentLineNbKey = $this->getRealCurrentLineNb(); $value = $this->parseBlock($this->getRealCurrentLineNb() + 1, $this->getNextEmbedBlock(), $flags); // Spec: Keys MUST be unique; first one wins. // But overwriting is allowed when a merge node is used in current block. if ($allowOverwrite || !isset($data[$key])) { $data[$key] = $value; } else { @trigger_error(sprintf('Duplicate key "%s" detected on line %d whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key, $realCurrentLineNbKey + 1), E_USER_DEPRECATED); } } } else { $value = $this->parseValue($values['value'], $flags, $context); // Spec: Keys MUST be unique; first one wins. // But overwriting is allowed when a merge node is used in current block. if ($allowOverwrite || !isset($data[$key])) { $data[$key] = $value; } else { @trigger_error(sprintf('Duplicate key "%s" detected on line %d whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key, $this->getRealCurrentLineNb() + 1), E_USER_DEPRECATED); } } if ($isRef) { $this->refs[$isRef] = $data[$key]; } } else { // multiple documents are not supported if ('---' === $this->currentLine) { throw new ParseException('Multiple documents are not supported.', $this->currentLineNb + 1, $this->currentLine); } // 1-liner optionally followed by newline(s) if (is_string($value) && $this->lines[0] === trim($value)) { try { Inline::$parsedLineNumber = $this->getRealCurrentLineNb(); $value = Inline::parse($this->lines[0], $flags, $this->refs); } catch (ParseException $e) { $e->setParsedLine($this->getRealCurrentLineNb() + 1); $e->setSnippet($this->currentLine); throw $e; } if (isset($mbEncoding)) { mb_internal_encoding($mbEncoding); } return $value; } switch (preg_last_error()) { case PREG_INTERNAL_ERROR: $error = 'Internal PCRE error.'; break; case PREG_BACKTRACK_LIMIT_ERROR: $error = 'pcre.backtrack_limit reached.'; break; case PREG_RECURSION_LIMIT_ERROR: $error = 'pcre.recursion_limit reached.'; break; case PREG_BAD_UTF8_ERROR: $error = 'Malformed UTF-8 data.'; break; case PREG_BAD_UTF8_OFFSET_ERROR: $error = 'Offset doesn\'t correspond to the begin of a valid UTF-8 code point.'; break; default: $error = 'Unable to parse.'; } throw new ParseException($error, $this->getRealCurrentLineNb() + 1, $this->currentLine); } } if (isset($mbEncoding)) { mb_internal_encoding($mbEncoding); } if (Yaml::PARSE_OBJECT_FOR_MAP & $flags && !is_object($data) && 'mapping' === $context) { $object = new \stdClass(); foreach ($data as $key => $value) { $object->$key = $value; } $data = $object; } return empty($data) ? null : $data; } private function parseBlock($offset, $yaml, $flags) { $skippedLineNumbers = $this->skippedLineNumbers; foreach ($this->locallySkippedLineNumbers as $lineNumber) { if ($lineNumber < $offset) { continue; } $skippedLineNumbers[] = $lineNumber; } $parser = new self($offset, $this->totalNumberOfLines, $skippedLineNumbers); $parser->refs = &$this->refs; return $parser->parse($yaml, $flags); } /** * Returns the current line number (takes the offset into account). * * @return int The current line number */ private function getRealCurrentLineNb() { $realCurrentLineNumber = $this->currentLineNb + $this->offset; foreach ($this->skippedLineNumbers as $skippedLineNumber) { if ($skippedLineNumber > $realCurrentLineNumber) { break; } ++$realCurrentLineNumber; } return $realCurrentLineNumber; } /** * Returns the current line indentation. * * @return int The current line indentation */ private function getCurrentLineIndentation() { return strlen($this->currentLine) - strlen(ltrim($this->currentLine, ' ')); } /** * Returns the next embed block of YAML. * * @param int $indentation The indent level at which the block is to be read, or null for default * @param bool $inSequence True if the enclosing data structure is a sequence * * @return string A YAML string * * @throws ParseException When indentation problem are detected */ private function getNextEmbedBlock($indentation = null, $inSequence = false) { $oldLineIndentation = $this->getCurrentLineIndentation(); $blockScalarIndentations = array(); if ($this->isBlockScalarHeader()) { $blockScalarIndentations[] = $this->getCurrentLineIndentation(); } if (!$this->moveToNextLine()) { return; } if (null === $indentation) { $newIndent = $this->getCurrentLineIndentation(); $unindentedEmbedBlock = $this->isStringUnIndentedCollectionItem(); if (!$this->isCurrentLineEmpty() && 0 === $newIndent && !$unindentedEmbedBlock) { throw new ParseException('Indentation problem.', $this->getRealCurrentLineNb() + 1, $this->currentLine); } } else { $newIndent = $indentation; } $data = array(); if ($this->getCurrentLineIndentation() >= $newIndent) { $data[] = substr($this->currentLine, $newIndent); } else { $this->moveToPreviousLine(); return; } if ($inSequence && $oldLineIndentation === $newIndent && isset($data[0][0]) && '-' === $data[0][0]) { // the previous line contained a dash but no item content, this line is a sequence item with the same indentation // and therefore no nested list or mapping $this->moveToPreviousLine(); return; } $isItUnindentedCollection = $this->isStringUnIndentedCollectionItem(); if (empty($blockScalarIndentations) && $this->isBlockScalarHeader()) { $blockScalarIndentations[] = $this->getCurrentLineIndentation(); } $previousLineIndentation = $this->getCurrentLineIndentation(); while ($this->moveToNextLine()) { $indent = $this->getCurrentLineIndentation(); // terminate all block scalars that are more indented than the current line if (!empty($blockScalarIndentations) && $indent < $previousLineIndentation && trim($this->currentLine) !== '') { foreach ($blockScalarIndentations as $key => $blockScalarIndentation) { if ($blockScalarIndentation >= $this->getCurrentLineIndentation()) { unset($blockScalarIndentations[$key]); } } } if (empty($blockScalarIndentations) && !$this->isCurrentLineComment() && $this->isBlockScalarHeader()) { $blockScalarIndentations[] = $this->getCurrentLineIndentation(); } $previousLineIndentation = $indent; if ($isItUnindentedCollection && !$this->isCurrentLineEmpty() && !$this->isStringUnIndentedCollectionItem() && $newIndent === $indent) { $this->moveToPreviousLine(); break; } if ($this->isCurrentLineBlank()) { $data[] = substr($this->currentLine, $newIndent); continue; } // we ignore "comment" lines only when we are not inside a scalar block if (empty($blockScalarIndentations) && $this->isCurrentLineComment()) { // remember ignored comment lines (they are used later in nested // parser calls to determine real line numbers) // // CAUTION: beware to not populate the global property here as it // will otherwise influence the getRealCurrentLineNb() call here // for consecutive comment lines and subsequent embedded blocks $this->locallySkippedLineNumbers[] = $this->getRealCurrentLineNb(); continue; } if ($indent >= $newIndent) { $data[] = substr($this->currentLine, $newIndent); } elseif (0 == $indent) { $this->moveToPreviousLine(); break; } else { throw new ParseException('Indentation problem.', $this->getRealCurrentLineNb() + 1, $this->currentLine); } } return implode("\n", $data); } /** * Moves the parser to the next line. * * @return bool */ private function moveToNextLine() { if ($this->currentLineNb >= count($this->lines) - 1) { return false; } $this->currentLine = $this->lines[++$this->currentLineNb]; return true; } /** * Moves the parser to the previous line. * * @return bool */ private function moveToPreviousLine() { if ($this->currentLineNb < 1) { return false; } $this->currentLine = $this->lines[--$this->currentLineNb]; return true; } /** * Parses a YAML value. * * @param string $value A YAML value * @param int $flags A bit field of PARSE_* constants to customize the YAML parser behavior * @param string $context The parser context (either sequence or mapping) * * @return mixed A PHP value * * @throws ParseException When reference does not exist */ private function parseValue($value, $flags, $context) { if (0 === strpos($value, '*')) { if (false !== $pos = strpos($value, '#')) { $value = substr($value, 1, $pos - 2); } else { $value = substr($value, 1); } if (!array_key_exists($value, $this->refs)) { throw new ParseException(sprintf('Reference "%s" does not exist.', $value), $this->currentLineNb + 1, $this->currentLine); } return $this->refs[$value]; } if (preg_match('/^'.self::TAG_PATTERN.self::BLOCK_SCALAR_HEADER_PATTERN.'$/', $value, $matches)) { $modifiers = isset($matches['modifiers']) ? $matches['modifiers'] : ''; $data = $this->parseBlockScalar($matches['separator'], preg_replace('#\d+#', '', $modifiers), (int) abs($modifiers)); if (isset($matches['tag']) && '!!binary' === $matches['tag']) { return Inline::evaluateBinaryScalar($data); } return $data; } try { $quotation = '' !== $value && ('"' === $value[0] || "'" === $value[0]) ? $value[0] : null; // do not take following lines into account when the current line is a quoted single line value if (null !== $quotation && preg_match('/^'.$quotation.'.*'.$quotation.'(\s*#.*)?$/', $value)) { return Inline::parse($value, $flags, $this->refs); } while ($this->moveToNextLine()) { // unquoted strings end before the first unindented line if (null === $quotation && $this->getCurrentLineIndentation() === 0) { $this->moveToPreviousLine(); break; } $value .= ' '.trim($this->currentLine); // quoted string values end with a line that is terminated with the quotation character if ('' !== $this->currentLine && substr($this->currentLine, -1) === $quotation) { break; } } Inline::$parsedLineNumber = $this->getRealCurrentLineNb(); $parsedValue = Inline::parse($value, $flags, $this->refs); if ('mapping' === $context && is_string($parsedValue) && '"' !== $value[0] && "'" !== $value[0] && '[' !== $value[0] && '{' !== $value[0] && '!' !== $value[0] && false !== strpos($parsedValue, ': ')) { throw new ParseException('A colon cannot be used in an unquoted mapping value.'); } return $parsedValue; } catch (ParseException $e) { $e->setParsedLine($this->getRealCurrentLineNb() + 1); $e->setSnippet($this->currentLine); throw $e; } } /** * Parses a block scalar. * * @param string $style The style indicator that was used to begin this block scalar (| or >) * @param string $chomping The chomping indicator that was used to begin this block scalar (+ or -) * @param int $indentation The indentation indicator that was used to begin this block scalar * * @return string The text value */ private function parseBlockScalar($style, $chomping = '', $indentation = 0) { $notEOF = $this->moveToNextLine(); if (!$notEOF) { return ''; } $isCurrentLineBlank = $this->isCurrentLineBlank(); $blockLines = array(); // leading blank lines are consumed before determining indentation while ($notEOF && $isCurrentLineBlank) { // newline only if not EOF if ($notEOF = $this->moveToNextLine()) { $blockLines[] = ''; $isCurrentLineBlank = $this->isCurrentLineBlank(); } } // determine indentation if not specified if (0 === $indentation) { if (preg_match('/^ +/', $this->currentLine, $matches)) { $indentation = strlen($matches[0]); } } if ($indentation > 0) { $pattern = sprintf('/^ {%d}(.*)$/', $indentation); while ( $notEOF && ( $isCurrentLineBlank || preg_match($pattern, $this->currentLine, $matches) ) ) { if ($isCurrentLineBlank && strlen($this->currentLine) > $indentation) { $blockLines[] = substr($this->currentLine, $indentation); } elseif ($isCurrentLineBlank) { $blockLines[] = ''; } else { $blockLines[] = $matches[1]; } // newline only if not EOF if ($notEOF = $this->moveToNextLine()) { $isCurrentLineBlank = $this->isCurrentLineBlank(); } } } elseif ($notEOF) { $blockLines[] = ''; } if ($notEOF) { $blockLines[] = ''; $this->moveToPreviousLine(); } elseif (!$notEOF && !$this->isCurrentLineLastLineInDocument()) { $blockLines[] = ''; } // folded style if ('>' === $style) { $text = ''; $previousLineIndented = false; $previousLineBlank = false; for ($i = 0, $blockLinesCount = count($blockLines); $i < $blockLinesCount; ++$i) { if ('' === $blockLines[$i]) { $text .= "\n"; $previousLineIndented = false; $previousLineBlank = true; } elseif (' ' === $blockLines[$i][0]) { $text .= "\n".$blockLines[$i]; $previousLineIndented = true; $previousLineBlank = false; } elseif ($previousLineIndented) { $text .= "\n".$blockLines[$i]; $previousLineIndented = false; $previousLineBlank = false; } elseif ($previousLineBlank || 0 === $i) { $text .= $blockLines[$i]; $previousLineIndented = false; $previousLineBlank = false; } else { $text .= ' '.$blockLines[$i]; $previousLineIndented = false; $previousLineBlank = false; } } } else { $text = implode("\n", $blockLines); } // deal with trailing newlines if ('' === $chomping) { $text = preg_replace('/\n+$/', "\n", $text); } elseif ('-' === $chomping) { $text = preg_replace('/\n+$/', '', $text); } return $text; } /** * Returns true if the next line is indented. * * @return bool Returns true if the next line is indented, false otherwise */ private function isNextLineIndented() { $currentIndentation = $this->getCurrentLineIndentation(); $EOF = !$this->moveToNextLine(); while (!$EOF && $this->isCurrentLineEmpty()) { $EOF = !$this->moveToNextLine(); } if ($EOF) { return false; } $ret = false; if ($this->getCurrentLineIndentation() > $currentIndentation) { $ret = true; } $this->moveToPreviousLine(); return $ret; } /** * Returns true if the current line is blank or if it is a comment line. * * @return bool Returns true if the current line is empty or if it is a comment line, false otherwise */ private function isCurrentLineEmpty() { return $this->isCurrentLineBlank() || $this->isCurrentLineComment(); } /** * Returns true if the current line is blank. * * @return bool Returns true if the current line is blank, false otherwise */ private function isCurrentLineBlank() { return '' == trim($this->currentLine, ' '); } /** * Returns true if the current line is a comment line. * * @return bool Returns true if the current line is a comment line, false otherwise */ private function isCurrentLineComment() { //checking explicitly the first char of the trim is faster than loops or strpos $ltrimmedLine = ltrim($this->currentLine, ' '); return '' !== $ltrimmedLine && $ltrimmedLine[0] === '#'; } private function isCurrentLineLastLineInDocument() { return ($this->offset + $this->currentLineNb) >= ($this->totalNumberOfLines - 1); } /** * Cleanups a YAML string to be parsed. * * @param string $value The input YAML string * * @return string A cleaned up YAML string */ private function cleanup($value) { $value = str_replace(array("\r\n", "\r"), "\n", $value); // strip YAML header $count = 0; $value = preg_replace('#^\%YAML[: ][\d\.]+.*\n#u', '', $value, -1, $count); $this->offset += $count; // remove leading comments $trimmedValue = preg_replace('#^(\#.*?\n)+#s', '', $value, -1, $count); if ($count == 1) { // items have been removed, update the offset $this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n"); $value = $trimmedValue; } // remove start of the document marker (---) $trimmedValue = preg_replace('#^\-\-\-.*?\n#s', '', $value, -1, $count); if ($count == 1) { // items have been removed, update the offset $this->offset += substr_count($value, "\n") - substr_count($trimmedValue, "\n"); $value = $trimmedValue; // remove end of the document marker (...) $value = preg_replace('#\.\.\.\s*$#', '', $value); } return $value; } /** * Returns true if the next line starts unindented collection. * * @return bool Returns true if the next line starts unindented collection, false otherwise */ private function isNextLineUnIndentedCollection() { $currentIndentation = $this->getCurrentLineIndentation(); $notEOF = $this->moveToNextLine(); while ($notEOF && $this->isCurrentLineEmpty()) { $notEOF = $this->moveToNextLine(); } if (false === $notEOF) { return false; } $ret = false; if ( $this->getCurrentLineIndentation() == $currentIndentation && $this->isStringUnIndentedCollectionItem() ) { $ret = true; } $this->moveToPreviousLine(); return $ret; } /** * Returns true if the string is un-indented collection item. * * @return bool Returns true if the string is un-indented collection item, false otherwise */ private function isStringUnIndentedCollectionItem() { return '-' === rtrim($this->currentLine) || 0 === strpos($this->currentLine, '- '); } /** * Tests whether or not the current line is the header of a block scalar. * * @return bool */ private function isBlockScalarHeader() { return (bool) preg_match('~'.self::BLOCK_SCALAR_HEADER_PATTERN.'$~', $this->currentLine); } } symfony/yaml/Escaper.php 0000604 00000007436 15247160545 0011324 0 ustar 00 <?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Yaml; /** * Escaper encapsulates escaping rules for single and double-quoted * YAML strings. * * @author Matthew Lewinski <matthew@lewinski.org> * * @internal */ class Escaper { // Characters that would cause a dumped string to require double quoting. const REGEX_CHARACTER_TO_ESCAPE = "[\\x00-\\x1f]|\xc2\x85|\xc2\xa0|\xe2\x80\xa8|\xe2\x80\xa9"; // Mapping arrays for escaping a double quoted string. The backslash is // first to ensure proper escaping because str_replace operates iteratively // on the input arrays. This ordering of the characters avoids the use of strtr, // which performs more slowly. private static $escapees = array('\\', '\\\\', '\\"', '"', "\x00", "\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07", "\x08", "\x09", "\x0a", "\x0b", "\x0c", "\x0d", "\x0e", "\x0f", "\x10", "\x11", "\x12", "\x13", "\x14", "\x15", "\x16", "\x17", "\x18", "\x19", "\x1a", "\x1b", "\x1c", "\x1d", "\x1e", "\x1f", "\xc2\x85", "\xc2\xa0", "\xe2\x80\xa8", "\xe2\x80\xa9"); private static $escaped = array('\\\\', '\\"', '\\\\', '\\"', '\\0', '\\x01', '\\x02', '\\x03', '\\x04', '\\x05', '\\x06', '\\a', '\\b', '\\t', '\\n', '\\v', '\\f', '\\r', '\\x0e', '\\x0f', '\\x10', '\\x11', '\\x12', '\\x13', '\\x14', '\\x15', '\\x16', '\\x17', '\\x18', '\\x19', '\\x1a', '\\e', '\\x1c', '\\x1d', '\\x1e', '\\x1f', '\\N', '\\_', '\\L', '\\P'); /** * Determines if a PHP value would require double quoting in YAML. * * @param string $value A PHP value * * @return bool True if the value would require double quotes */ public static function requiresDoubleQuoting($value) { return preg_match('/'.self::REGEX_CHARACTER_TO_ESCAPE.'/u', $value); } /** * Escapes and surrounds a PHP value with double quotes. * * @param string $value A PHP value * * @return string The quoted, escaped string */ public static function escapeWithDoubleQuotes($value) { return sprintf('"%s"', str_replace(self::$escapees, self::$escaped, $value)); } /** * Determines if a PHP value would require single quoting in YAML. * * @param string $value A PHP value * * @return bool True if the value would require single quotes */ public static function requiresSingleQuoting($value) { // Determines if a PHP value is entirely composed of a value that would // require single quoting in YAML. if (in_array(strtolower($value), array('null', '~', 'true', 'false', 'y', 'n', 'yes', 'no', 'on', 'off'))) { return true; } // Determines if the PHP value contains any single characters that would // cause it to require single quoting in YAML. return preg_match('/[ \s \' " \: \{ \} \[ \] , & \* \# \?] | \A[ \- ? | < > = ! % @ ` ]/x', $value); } /** * Escapes and surrounds a PHP value with single quotes. * * @param string $value A PHP value * * @return string The quoted, escaped string */ public static function escapeWithSingleQuotes($value) { return sprintf("'%s'", str_replace('\'', '\'\'', $value)); } }
| ver. 1.4 |
Github
|
.
| PHP 7.4.33 | Generation time: 0 |
proxy
|
phpinfo
|
Settings