updated backend

This commit is contained in:
Torsten 2020-01-17 10:58:01 +01:00
parent 1fea0f4fe7
commit 11521c2339
3459 changed files with 72735 additions and 168535 deletions

View file

@ -1,3 +0,0 @@
vendor/
composer.lock
phpunit.xml

View file

@ -1,6 +1,53 @@
CHANGELOG
=========
4.4.0
-----
* Added support for parsing the inline notation spanning multiple lines.
* Added support to dump `null` as `~` by using the `Yaml::DUMP_NULL_AS_TILDE` flag.
* deprecated accepting STDIN implicitly when using the `lint:yaml` command, use `lint:yaml -` (append a dash) instead to make it explicit.
4.3.0
-----
* Using a mapping inside a multi-line string is deprecated and will throw a `ParseException` in 5.0.
4.2.0
-----
* added support for multiple files or directories in `LintCommand`
4.0.0
-----
* The behavior of the non-specific tag `!` is changed and now forces
non-evaluating your values.
* complex mappings will throw a `ParseException`
* support for the comma as a group separator for floats has been dropped, use
the underscore instead
* support for the `!!php/object` tag has been dropped, use the `!php/object`
tag instead
* duplicate mapping keys throw a `ParseException`
* non-string mapping keys throw a `ParseException`, use the `Yaml::PARSE_KEYS_AS_STRINGS`
flag to cast them to strings
* `%` at the beginning of an unquoted string throw a `ParseException`
* mappings with a colon (`:`) that is not followed by a whitespace throw a
`ParseException`
* the `Dumper::setIndentation()` method has been removed
* being able to pass boolean options to the `Yaml::parse()`, `Yaml::dump()`,
`Parser::parse()`, and `Dumper::dump()` methods to configure the behavior of
the parser and dumper is no longer supported, pass bitmask flags instead
* the constructor arguments of the `Parser` class have been removed
* the `Inline` class is internal and no longer part of the BC promise
* removed support for the `!str` tag, use the `!!str` tag instead
* added support for tagged scalars.
```yml
Yaml::parse('!foo bar', Yaml::PARSE_CUSTOM_TAGS);
// returns TaggedValue('foo', 'bar');
```
3.4.0
-----
@ -113,7 +160,7 @@ CHANGELOG
* 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);
Yaml::dump(['foo' => new A(), 'bar' => 1], 0, 0, Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE | Yaml::DUMP_OBJECT);
```
3.0.0

View file

@ -14,6 +14,7 @@ namespace Symfony\Component\Yaml\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
@ -38,7 +39,7 @@ class LintCommand extends Command
private $directoryIteratorProvider;
private $isReadableProvider;
public function __construct($name = null, $directoryIteratorProvider = null, $isReadableProvider = null)
public function __construct(string $name = null, callable $directoryIteratorProvider = null, callable $isReadableProvider = null)
{
parent::__construct($name);
@ -53,7 +54,7 @@ class LintCommand extends Command
{
$this
->setDescription('Lints a file and outputs encountered errors')
->addArgument('filename', null, 'A file or a directory or STDIN')
->addArgument('filename', InputArgument::IS_ARRAY, 'A file, a directory or "-" for reading from STDIN')
->addOption('format', null, InputOption::VALUE_REQUIRED, 'The output format', 'txt')
->addOption('parse-tags', null, InputOption::VALUE_NONE, 'Parse custom tags')
->setHelp(<<<EOF
@ -62,7 +63,7 @@ the first encountered syntax error.
You can validates YAML contents passed from STDIN:
<info>cat filename | php %command.full_name%</info>
<info>cat filename | php %command.full_name% -</info>
You can also validate the syntax of a file:
@ -81,32 +82,41 @@ EOF
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$filename = $input->getArgument('filename');
$filenames = (array) $input->getArgument('filename');
$this->format = $input->getOption('format');
$this->displayCorrectFiles = $output->isVerbose();
$flags = $input->getOption('parse-tags') ? Yaml::PARSE_CUSTOM_TAGS : 0;
if (!$filename) {
if (!$stdin = $this->getStdin()) {
throw new RuntimeException('Please provide a filename or pipe file content to STDIN.');
if (['-'] === $filenames) {
return $this->display($io, [$this->validate(file_get_contents('php://stdin'), $flags)]);
}
// @deprecated to be removed in 5.0
if (!$filenames) {
if (0 === ftell(STDIN)) {
@trigger_error('Piping content from STDIN to the "lint:yaml" command without passing the dash symbol "-" as argument is deprecated since Symfony 4.4.', E_USER_DEPRECATED);
return $this->display($io, [$this->validate(file_get_contents('php://stdin'), $flags)]);
}
return $this->display($io, array($this->validate($stdin, $flags)));
throw new RuntimeException('Please provide a filename or pipe file content to STDIN.');
}
if (!$this->isReadable($filename)) {
throw new RuntimeException(sprintf('File or directory "%s" is not readable.', $filename));
}
$filesInfo = [];
foreach ($filenames as $filename) {
if (!$this->isReadable($filename)) {
throw new RuntimeException(sprintf('File or directory "%s" is not readable.', $filename));
}
$filesInfo = array();
foreach ($this->getFiles($filename) as $file) {
$filesInfo[] = $this->validate(file_get_contents($file), $flags, $file);
foreach ($this->getFiles($filename) as $file) {
$filesInfo[] = $this->validate(file_get_contents($file), $flags, $file);
}
}
return $this->display($io, $filesInfo);
}
private function validate($content, $flags, $file = null)
private function validate(string $content, int $flags, string $file = null)
{
$prevErrorHandler = set_error_handler(function ($level, $message, $file, $line) use (&$prevErrorHandler) {
if (E_USER_DEPRECATED === $level) {
@ -119,15 +129,15 @@ EOF
try {
$this->getParser()->parse($content, Yaml::PARSE_CONSTANT | $flags);
} catch (ParseException $e) {
return array('file' => $file, 'line' => $e->getParsedLine(), 'valid' => false, 'message' => $e->getMessage());
return ['file' => $file, 'line' => $e->getParsedLine(), 'valid' => false, 'message' => $e->getMessage()];
} finally {
restore_error_handler();
}
return array('file' => $file, 'valid' => true);
return ['file' => $file, 'valid' => true];
}
private function display(SymfonyStyle $io, array $files)
private function display(SymfonyStyle $io, array $files): int
{
switch ($this->format) {
case 'txt':
@ -139,10 +149,11 @@ EOF
}
}
private function displayTxt(SymfonyStyle $io, array $filesInfo)
private function displayTxt(SymfonyStyle $io, array $filesInfo): int
{
$countFiles = \count($filesInfo);
$erroredFiles = 0;
$suggestTagOption = false;
foreach ($filesInfo as $info) {
if ($info['valid'] && $this->displayCorrectFiles) {
@ -151,19 +162,23 @@ EOF
++$erroredFiles;
$io->text('<error> ERROR </error>'.($info['file'] ? sprintf(' in %s', $info['file']) : ''));
$io->text(sprintf('<error> >> %s</error>', $info['message']));
if (false !== strpos($info['message'], 'PARSE_CUSTOM_TAGS')) {
$suggestTagOption = true;
}
}
}
if (0 === $erroredFiles) {
$io->success(sprintf('All %d YAML files contain valid syntax.', $countFiles));
} else {
$io->warning(sprintf('%d YAML files have valid syntax and %d contain errors.', $countFiles - $erroredFiles, $erroredFiles));
$io->warning(sprintf('%d YAML files have valid syntax and %d contain errors.%s', $countFiles - $erroredFiles, $erroredFiles, $suggestTagOption ? ' Use the --parse-tags option if you want parse custom tags.' : ''));
}
return min($erroredFiles, 1);
}
private function displayJson(SymfonyStyle $io, array $filesInfo)
private function displayJson(SymfonyStyle $io, array $filesInfo): int
{
$errors = 0;
@ -172,6 +187,10 @@ EOF
if (!$v['valid']) {
++$errors;
}
if (isset($v['message']) && false !== strpos($v['message'], 'PARSE_CUSTOM_TAGS')) {
$v['message'] .= ' Use the --parse-tags option if you want parse custom tags.';
}
});
$io->writeln(json_encode($filesInfo, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
@ -179,7 +198,7 @@ EOF
return min($errors, 1);
}
private function getFiles($fileOrDirectory)
private function getFiles(string $fileOrDirectory): iterable
{
if (is_file($fileOrDirectory)) {
yield new \SplFileInfo($fileOrDirectory);
@ -188,7 +207,7 @@ EOF
}
foreach ($this->getDirectoryIterator($fileOrDirectory) as $file) {
if (!\in_array($file->getExtension(), array('yml', 'yaml'))) {
if (!\in_array($file->getExtension(), ['yml', 'yaml'])) {
continue;
}
@ -196,21 +215,7 @@ EOF
}
}
private function getStdin()
{
if (0 !== ftell(STDIN)) {
return;
}
$inputs = '';
while (!feof(STDIN)) {
$inputs .= fread(STDIN, 1024);
}
return $inputs;
}
private function getParser()
private function getParser(): Parser
{
if (!$this->parser) {
$this->parser = new Parser();
@ -219,7 +224,7 @@ EOF
return $this->parser;
}
private function getDirectoryIterator($directory)
private function getDirectoryIterator(string $directory): iterable
{
$default = function ($directory) {
return new \RecursiveIteratorIterator(
@ -229,20 +234,20 @@ EOF
};
if (null !== $this->directoryIteratorProvider) {
return \call_user_func($this->directoryIteratorProvider, $directory, $default);
return ($this->directoryIteratorProvider)($directory, $default);
}
return $default($directory);
}
private function isReadable($fileOrDirectory)
private function isReadable(string $fileOrDirectory): bool
{
$default = function ($fileOrDirectory) {
return is_readable($fileOrDirectory);
};
if (null !== $this->isReadableProvider) {
return \call_user_func($this->isReadableProvider, $fileOrDirectory, $default);
return ($this->isReadableProvider)($fileOrDirectory, $default);
}
return $default($fileOrDirectory);

View file

@ -11,12 +11,14 @@
namespace Symfony\Component\Yaml;
use Symfony\Component\Yaml\Tag\TaggedValue;
/**
* Dumper dumps PHP variables to YAML strings.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since version 3.4
* @final
*/
class Dumper
{
@ -27,10 +29,7 @@ class Dumper
*/
protected $indentation;
/**
* @param int $indentation
*/
public function __construct($indentation = 4)
public function __construct(int $indentation = 4)
{
if ($indentation < 1) {
throw new \InvalidArgumentException('The indentation must be greater than zero.');
@ -39,20 +38,6 @@ class Dumper
$this->indentation = $indentation;
}
/**
* Sets the indentation.
*
* @param int $num The amount of spaces to use for indentation of nested nodes
*
* @deprecated since version 3.1, to be removed in 4.0. Pass the indentation to the constructor instead.
*/
public function setIndentation($num)
{
@trigger_error('The '.__METHOD__.' method is deprecated since Symfony 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.
*
@ -63,26 +48,8 @@ class Dumper
*
* @return string The YAML representation of the PHP value
*/
public function dump($input, $inline = 0, $indent = 0, $flags = 0)
public function dump($input, int $inline = 0, int $indent = 0, int $flags = 0): string
{
if (\is_bool($flags)) {
@trigger_error('Passing a boolean flag to toggle exception handling is deprecated since Symfony 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 Symfony 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) : '';
$dumpObjectAsInlineMap = true;
@ -91,7 +58,7 @@ class Dumper
$dumpObjectAsInlineMap = empty((array) $input);
}
if ($inline <= 0 || (!\is_array($input) && $dumpObjectAsInlineMap) || empty($input)) {
if ($inline <= 0 || (!\is_array($input) && !$input instanceof TaggedValue && $dumpObjectAsInlineMap) || empty($input)) {
$output .= $prefix.Inline::dump($input, $flags);
} else {
$dumpAsMap = Inline::isHash($input);
@ -103,13 +70,39 @@ class Dumper
$blockIndentationIndicator = (' ' === substr($value, 0, 1)) ? (string) $this->indentation : '';
$output .= sprintf("%s%s%s |%s\n", $prefix, $dumpAsMap ? Inline::dump($key, $flags).':' : '-', '', $blockIndentationIndicator);
foreach (preg_split('/\n|\r\n/', $value) as $row) {
foreach (explode("\n", $value) as $row) {
$output .= sprintf("%s%s%s\n", $prefix, str_repeat(' ', $this->indentation), $row);
}
continue;
}
if ($value instanceof TaggedValue) {
$output .= sprintf('%s%s !%s', $prefix, $dumpAsMap ? Inline::dump($key, $flags).':' : '-', $value->getTag());
if ($inline >= 1 && Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK & $flags && \is_string($value->getValue()) && false !== strpos($value->getValue(), "\n") && false === strpos($value->getValue(), "\r\n")) {
// If the first line starts with a space character, the spec requires a blockIndicationIndicator
// http://www.yaml.org/spec/1.2/spec.html#id2793979
$blockIndentationIndicator = (' ' === substr($value->getValue(), 0, 1)) ? (string) $this->indentation : '';
$output .= sprintf(" |%s\n", $blockIndentationIndicator);
foreach (explode("\n", $value->getValue()) as $row) {
$output .= sprintf("%s%s%s\n", $prefix, str_repeat(' ', $this->indentation), $row);
}
continue;
}
if ($inline - 1 <= 0 || null === $value->getValue() || is_scalar($value->getValue())) {
$output .= ' '.$this->dump($value->getValue(), $inline - 1, 0, $flags)."\n";
} else {
$output .= "\n";
$output .= $this->dump($value->getValue(), $inline - 1, $dumpAsMap ? $indent + $this->indentation : $indent + 2, $flags);
}
continue;
}
$dumpObjectAsInlineMap = true;
if (Yaml::DUMP_OBJECT_AS_MAP & $flags && ($value instanceof \ArrayObject || $value instanceof \stdClass)) {

View file

@ -28,20 +28,20 @@ class Escaper
// 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('\\', '\\\\', '\\"', '"',
private static $escapees = ['\\', '\\\\', '\\"', '"',
"\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('\\\\', '\\"', '\\\\', '\\"',
];
private static $escaped = ['\\\\', '\\"', '\\\\', '\\"',
'\\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.
@ -50,7 +50,7 @@ class Escaper
*
* @return bool True if the value would require double quotes
*/
public static function requiresDoubleQuoting($value)
public static function requiresDoubleQuoting(string $value): bool
{
return 0 < preg_match('/'.self::REGEX_CHARACTER_TO_ESCAPE.'/u', $value);
}
@ -62,7 +62,7 @@ class Escaper
*
* @return string The quoted, escaped string
*/
public static function escapeWithDoubleQuotes($value)
public static function escapeWithDoubleQuotes(string $value): string
{
return sprintf('"%s"', str_replace(self::$escapees, self::$escaped, $value));
}
@ -74,11 +74,11 @@ class Escaper
*
* @return bool True if the value would require single quotes
*/
public static function requiresSingleQuoting($value)
public static function requiresSingleQuoting(string $value): bool
{
// 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'))) {
if (\in_array(strtolower($value), ['null', '~', 'true', 'false', 'y', 'n', 'yes', 'no', 'on', 'off'])) {
return true;
}
@ -94,7 +94,7 @@ class Escaper
*
* @return string The quoted, escaped string
*/
public static function escapeWithSingleQuotes($value)
public static function escapeWithSingleQuotes(string $value): string
{
return sprintf("'%s'", str_replace('\'', '\'\'', $value));
}

View file

@ -16,6 +16,6 @@ namespace Symfony\Component\Yaml\Exception;
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface ExceptionInterface
interface ExceptionInterface extends \Throwable
{
}

View file

@ -30,7 +30,7 @@ class ParseException extends RuntimeException
* @param string|null $parsedFile The file name where the error occurred
* @param \Exception|null $previous The previous exception
*/
public function __construct($message, $parsedLine = -1, $snippet = null, $parsedFile = null, \Exception $previous = null)
public function __construct(string $message, int $parsedLine = -1, string $snippet = null, string $parsedFile = null, \Throwable $previous = null)
{
$this->parsedFile = $parsedFile;
$this->parsedLine = $parsedLine;

View file

@ -34,12 +34,7 @@ class Inline
private static $objectForMap = false;
private static $constantSupport = false;
/**
* @param int $flags
* @param int|null $parsedLineNumber
* @param string|null $parsedFilename
*/
public static function initialize($flags, $parsedLineNumber = null, $parsedFilename = null)
public static function initialize(int $flags, int $parsedLineNumber = null, string $parsedFilename = null)
{
self::$exceptionOnInvalidType = (bool) (Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE & $flags);
self::$objectSupport = (bool) (Yaml::PARSE_OBJECT & $flags);
@ -63,40 +58,8 @@ class Inline
*
* @throws ParseException
*/
public static function parse($value, $flags = 0, $references = array())
public static function parse(string $value = null, int $flags = 0, array $references = [])
{
if (\is_bool($flags)) {
@trigger_error('Passing a boolean flag to toggle exception handling is deprecated since Symfony 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 Symfony 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 Symfony 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::initialize($flags);
$value = trim($value);
@ -110,35 +73,37 @@ class Inline
mb_internal_encoding('ASCII');
}
$i = 0;
$tag = self::parseTag($value, $i, $flags);
switch ($value[$i]) {
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, $i, null === $tag, $references);
}
try {
$i = 0;
$tag = self::parseTag($value, $i, $flags);
switch ($value[$i]) {
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, $i, null === $tag, $references);
}
if (null !== $tag) {
return new TaggedValue($tag, $result);
}
// 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)), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
}
// 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)), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
}
if (null !== $tag && '' !== $tag) {
return new TaggedValue($tag, $result);
}
if (isset($mbEncoding)) {
mb_internal_encoding($mbEncoding);
return $result;
} finally {
if (isset($mbEncoding)) {
mb_internal_encoding($mbEncoding);
}
}
return $result;
}
/**
@ -151,33 +116,15 @@ class Inline
*
* @throws DumpException When trying to dump PHP resource
*/
public static function dump($value, $flags = 0)
public static function dump($value, int $flags = 0): string
{
if (\is_bool($flags)) {
@trigger_error('Passing a boolean flag to toggle exception handling is deprecated since Symfony 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 Symfony 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';
return self::dumpNull($flags);
case $value instanceof \DateTimeInterface:
return $value->format('c');
case \is_object($value):
@ -190,18 +137,24 @@ class Inline
}
if (Yaml::DUMP_OBJECT_AS_MAP & $flags && ($value instanceof \stdClass || $value instanceof \ArrayObject)) {
return self::dumpArray($value, $flags & ~Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE);
$output = [];
foreach ($value as $key => $val) {
$output[] = sprintf('%s: %s', self::dump($key, $flags), self::dump($val, $flags));
}
return sprintf('{ %s }', implode(', ', $output));
}
if (Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE & $flags) {
throw new DumpException('Object support when dumping a YAML file has been disabled.');
}
return 'null';
return self::dumpNull($flags);
case \is_array($value):
return self::dumpArray($value, $flags);
case null === $value:
return 'null';
return self::dumpNull($flags);
case true === $value:
return 'true';
case false === $value:
@ -248,13 +201,11 @@ class Inline
/**
* Check if given array is hash or just normal indexed array.
*
* @internal
*
* @param array|\ArrayObject|\stdClass $value The PHP array or array-like object to check
*
* @return bool true if value is hash array, false otherwise
*/
public static function isHash($value)
public static function isHash($value): bool
{
if ($value instanceof \stdClass || $value instanceof \ArrayObject) {
return true;
@ -279,11 +230,11 @@ class Inline
*
* @return string The YAML string representing the PHP array
*/
private static function dumpArray($value, $flags)
private static function dumpArray(array $value, int $flags): string
{
// array
if (($value || Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE & $flags) && !self::isHash($value)) {
$output = array();
$output = [];
foreach ($value as $val) {
$output[] = self::dump($val, $flags);
}
@ -292,7 +243,7 @@ class Inline
}
// hash
$output = array();
$output = [];
foreach ($value as $key => $val) {
$output[] = sprintf('%s: %s', self::dump($key, $flags), self::dump($val, $flags));
}
@ -300,32 +251,32 @@ class Inline
return sprintf('{ %s }', implode(', ', $output));
}
private static function dumpNull(int $flags): string
{
if (Yaml::DUMP_NULL_AS_TILDE & $flags) {
return '~';
}
return 'null';
}
/**
* Parses a YAML scalar.
*
* @param string $scalar
* @param int $flags
* @param string[] $delimiters
* @param int &$i
* @param bool $evaluate
* @param array $references
*
* @return string
* @return mixed
*
* @throws ParseException When malformed inline YAML string is parsed
*
* @internal
*/
public static function parseScalar($scalar, $flags = 0, $delimiters = null, &$i = 0, $evaluate = true, $references = array(), $legacyOmittedKeySupport = false)
public static function parseScalar(string $scalar, int $flags = 0, array $delimiters = null, int &$i = 0, bool $evaluate = true, array $references = [])
{
if (\in_array($scalar[$i], array('"', "'"))) {
if (\in_array($scalar[$i], ['"', "'"])) {
// quoted scalar
$output = self::parseQuotedScalar($scalar, $i);
if (null !== $delimiters) {
$tmp = ltrim(substr($scalar, $i), ' ');
$tmp = ltrim(substr($scalar, $i), " \n");
if ('' === $tmp) {
throw new ParseException(sprintf('Unexpected end of line, expected one of "%s".', implode($delimiters)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
throw new ParseException(sprintf('Unexpected end of line, expected one of "%s".', implode('', $delimiters)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
}
if (!\in_array($tmp[0], $delimiters)) {
throw new ParseException(sprintf('Unexpected characters (%s).', substr($scalar, $i)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
@ -341,22 +292,19 @@ class Inline
if (Parser::preg_match('/[ \t]+#/', $output, $match, PREG_OFFSET_CAPTURE)) {
$output = substr($output, 0, $match[0][1]);
}
} elseif (Parser::preg_match('/^(.'.($legacyOmittedKeySupport ? '+' : '*').'?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match)) {
} elseif (Parser::preg_match('/^(.*?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match)) {
$output = $match[1];
$i += \strlen($output);
$output = trim($output);
} else {
throw new ParseException(sprintf('Malformed inline YAML string: %s.', $scalar), self::$parsedLineNumber + 1, null, self::$parsedFilename);
}
// 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])) {
if ($output && ('@' === $output[0] || '`' === $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]), self::$parsedLineNumber + 1, $output, self::$parsedFilename);
}
if ($output && '%' === $output[0]) {
@trigger_error(self::getDeprecationMessage(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);
}
@ -368,14 +316,9 @@ class Inline
/**
* 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)
private static function parseQuotedScalar(string $scalar, int &$i): string
{
if (!Parser::preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match)) {
throw new ParseException(sprintf('Malformed inline YAML string: %s.', substr($scalar, $i)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
@ -398,18 +341,11 @@ class Inline
/**
* 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())
private static function parseSequence(string $sequence, int $flags, int &$i = 0, array $references = []): array
{
$output = array();
$output = [];
$len = \strlen($sequence);
++$i;
@ -435,8 +371,8 @@ class Inline
$value = self::parseMapping($sequence, $flags, $i, $references);
break;
default:
$isQuoted = \in_array($sequence[$i], array('"', "'"));
$value = self::parseScalar($sequence, $flags, array(',', ']'), $i, null === $tag, $references);
$isQuoted = \in_array($sequence[$i], ['"', "'"]);
$value = self::parseScalar($sequence, $flags, [',', ']'], $i, null === $tag, $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, ': ')) {
@ -452,7 +388,7 @@ class Inline
--$i;
}
if (null !== $tag) {
if (null !== $tag && '' !== $tag) {
$value = new TaggedValue($tag, $value);
}
@ -467,18 +403,13 @@ class Inline
/**
* 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())
private static function parseMapping(string $mapping, int $flags, int &$i = 0, array $references = [])
{
$output = array();
$output = [];
$len = \strlen($mapping);
++$i;
$allowOverwrite = false;
@ -488,6 +419,7 @@ class Inline
switch ($mapping[$i]) {
case ' ':
case ',':
case "\n":
++$i;
continue 2;
case '}':
@ -499,27 +431,28 @@ class Inline
}
// key
$isKeyQuoted = \in_array($mapping[$i], array('"', "'"), true);
$key = self::parseScalar($mapping, $flags, array(':', ' '), $i, false, array(), true);
$offsetBeforeKeyParsing = $i;
$isKeyQuoted = \in_array($mapping[$i], ['"', "'"], true);
$key = self::parseScalar($mapping, $flags, [':', ' '], $i, false, []);
if (':' !== $key && false === $i = strpos($mapping, ':', $i)) {
break;
if ($offsetBeforeKeyParsing === $i) {
throw new ParseException('Missing mapping key.', self::$parsedLineNumber + 1, $mapping);
}
if (':' === $key) {
@trigger_error(self::getDeprecationMessage('Omitting the key of a mapping is deprecated and will throw a ParseException in 4.0.'), E_USER_DEPRECATED);
if (false === $i = strpos($mapping, ':', $i)) {
break;
}
if (!$isKeyQuoted) {
$evaluatedKey = self::evaluateScalar($key, $flags, $references);
if ('' !== $key && $evaluatedKey !== $key && !\is_string($evaluatedKey) && !\is_int($evaluatedKey)) {
@trigger_error(self::getDeprecationMessage('Implicit casting of incompatible mapping keys to strings is deprecated since Symfony 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0. Quote your evaluable mapping keys instead.'), E_USER_DEPRECATED);
throw new ParseException('Implicit casting of incompatible mapping keys to strings is not supported. Quote your evaluable mapping keys instead.', self::$parsedLineNumber + 1, $mapping);
}
}
if (':' !== $key && !$isKeyQuoted && (!isset($mapping[$i + 1]) || !\in_array($mapping[$i + 1], array(' ', ',', '[', ']', '{', '}'), true))) {
@trigger_error(self::getDeprecationMessage('Using a colon after an unquoted mapping key that is not followed by an indication character (i.e. " ", ",", "[", "]", "{", "}") is deprecated since Symfony 3.2 and will throw a ParseException in 4.0.'), E_USER_DEPRECATED);
if (!$isKeyQuoted && (!isset($mapping[$i + 1]) || !\in_array($mapping[$i + 1], [' ', ',', '[', ']', '{', '}', "\n"], true))) {
throw new ParseException('Colons must be followed by a space or an indication character (i.e. " ", ",", "[", "]", "{", "}").', self::$parsedLineNumber + 1, $mapping);
}
if ('<<' === $key) {
@ -527,7 +460,7 @@ class Inline
}
while ($i < $len) {
if (':' === $mapping[$i] || ' ' === $mapping[$i]) {
if (':' === $mapping[$i] || ' ' === $mapping[$i] || "\n" === $mapping[$i]) {
++$i;
continue;
@ -553,7 +486,7 @@ class Inline
$output[$key] = $value;
}
} elseif (isset($output[$key])) {
@trigger_error(self::getDeprecationMessage(sprintf('Duplicate key "%s" detected whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since Symfony 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key)), E_USER_DEPRECATED);
throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), self::$parsedLineNumber + 1, $mapping);
}
break;
case '{':
@ -572,11 +505,11 @@ class Inline
$output[$key] = $value;
}
} elseif (isset($output[$key])) {
@trigger_error(self::getDeprecationMessage(sprintf('Duplicate key "%s" detected whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since Symfony 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key)), E_USER_DEPRECATED);
throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), self::$parsedLineNumber + 1, $mapping);
}
break;
default:
$value = self::parseScalar($mapping, $flags, array(',', '}'), $i, null === $tag, $references);
$value = self::parseScalar($mapping, $flags, [',', '}', "\n"], $i, null === $tag, $references);
// Spec: Keys MUST be unique; first one wins.
// Parser cannot abort this mapping earlier, since lines
// are processed sequentially.
@ -590,7 +523,7 @@ class Inline
$output[$key] = $value;
}
} elseif (isset($output[$key])) {
@trigger_error(self::getDeprecationMessage(sprintf('Duplicate key "%s" detected whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since Symfony 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key)), E_USER_DEPRECATED);
throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), self::$parsedLineNumber + 1, $mapping);
}
--$i;
}
@ -606,15 +539,11 @@ class Inline
/**
* Evaluates scalars and replaces magic values.
*
* @param string $scalar
* @param int $flags
* @param array $references
*
* @return mixed The evaluated 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())
private static function evaluateScalar(string $scalar, int $flags, array $references = [])
{
$scalar = trim($scalar);
$scalarLower = strtolower($scalar);
@ -631,7 +560,7 @@ class Inline
throw new ParseException('A reference must contain at least one character.', self::$parsedLineNumber + 1, $value, self::$parsedFilename);
}
if (!array_key_exists($value, $references)) {
if (!\array_key_exists($value, $references)) {
throw new ParseException(sprintf('Reference "%s" does not exist.', $value), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
}
@ -642,47 +571,17 @@ class Inline
case 'null' === $scalarLower:
case '' === $scalar:
case '~' === $scalar:
return;
return null;
case 'true' === $scalarLower:
return true;
case 'false' === $scalarLower:
return false;
case '!' === $scalar[0]:
switch (true) {
case 0 === strpos($scalar, '!str'):
@trigger_error(self::getDeprecationMessage('Support for the !str tag is deprecated since Symfony 3.4. Use the !!str tag instead.'), E_USER_DEPRECATED);
return (string) substr($scalar, 5);
case 0 === strpos($scalar, '!!str '):
return (string) substr($scalar, 6);
case 0 === strpos($scalar, '! '):
@trigger_error(self::getDeprecationMessage('Using the non-specific tag "!" is deprecated since Symfony 3.4 as its behavior will change in 4.0. It will force non-evaluating your values in 4.0. Use plain integers or !!float instead.'), E_USER_DEPRECATED);
return (int) self::parseScalar(substr($scalar, 2), $flags);
case 0 === strpos($scalar, '!php/object:'):
if (self::$objectSupport) {
@trigger_error(self::getDeprecationMessage('The !php/object: tag to indicate dumped PHP objects is deprecated since Symfony 3.4 and will be removed in 4.0. Use the !php/object (without the colon) tag instead.'), E_USER_DEPRECATED);
return unserialize(substr($scalar, 12));
}
if (self::$exceptionOnInvalidType) {
throw new ParseException('Object support when parsing a YAML file has been disabled.', self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
}
return;
case 0 === strpos($scalar, '!!php/object:'):
if (self::$objectSupport) {
@trigger_error(self::getDeprecationMessage('The !!php/object: tag to indicate dumped PHP objects is deprecated since Symfony 3.1 and will be removed in 4.0. Use the !php/object (without the colon) 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.', self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
}
return;
return substr($scalar, 2);
case 0 === strpos($scalar, '!php/object'):
if (self::$objectSupport) {
return unserialize(self::parseScalar(substr($scalar, 12)));
@ -692,22 +591,7 @@ class Inline
throw new ParseException('Object support when parsing a YAML file has been disabled.', self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
}
return;
case 0 === strpos($scalar, '!php/const:'):
if (self::$constantSupport) {
@trigger_error(self::getDeprecationMessage('The !php/const: tag to indicate dumped PHP constants is deprecated since Symfony 3.4 and will be removed in 4.0. Use the !php/const (without the colon) tag instead.'), E_USER_DEPRECATED);
if (\defined($const = substr($scalar, 11))) {
return \constant($const);
}
throw new ParseException(sprintf('The constant "%s" is not defined.', $const), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
}
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), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
}
return;
return null;
case 0 === strpos($scalar, '!php/const'):
if (self::$constantSupport) {
$i = 0;
@ -721,23 +605,23 @@ class Inline
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), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
}
return;
return null;
case 0 === strpos($scalar, '!!float '):
return (float) substr($scalar, 8);
case 0 === strpos($scalar, '!!binary '):
return self::evaluateBinaryScalar(substr($scalar, 9));
default:
@trigger_error(self::getDeprecationMessage(sprintf('Using the unquoted scalar value "%s" is deprecated since Symfony 3.3 and will be considered as a tagged value in 4.0. You must quote it.', $scalar)), E_USER_DEPRECATED);
throw new ParseException(sprintf('The string "%s" could not be parsed as it uses an unsupported built-in tag.', $scalar), self::$parsedLineNumber, $scalar, self::$parsedFilename);
}
// Optimize for returning strings.
// no break
case '+' === $scalar[0] || '-' === $scalar[0] || '.' === $scalar[0] || is_numeric($scalar[0]):
if (Parser::preg_match('{^[+-]?[0-9][0-9_]*$}', $scalar)) {
$scalar = str_replace('_', '', (string) $scalar);
}
switch (true) {
case Parser::preg_match('{^[+-]?[0-9][0-9_]*$}', $scalar):
$scalar = str_replace('_', '', (string) $scalar);
// omitting the break / return as integers are handled in the next case
// no break
case ctype_digit($scalar):
$raw = $scalar;
$cast = (int) $scalar;
@ -747,7 +631,7 @@ class Inline
$raw = $scalar;
$cast = (int) $scalar;
return '0' == $scalar[1] ? octdec($scalar) : (((string) $raw === (string) $cast) ? $cast : $raw);
return '0' == $scalar[1] ? -octdec(substr($scalar, 1)) : (($raw === (string) $cast) ? $cast : $raw);
case is_numeric($scalar):
case Parser::preg_match(self::getHexRegex(), $scalar):
$scalar = str_replace('_', '', $scalar);
@ -758,13 +642,8 @@ class Inline
return -log(0);
case '-.inf' === $scalarLower:
return log(0);
case Parser::preg_match('/^(-|\+)?[0-9][0-9,]*(\.[0-9_]+)?$/', $scalar):
case Parser::preg_match('/^(-|\+)?[0-9][0-9_]*(\.[0-9_]+)?$/', $scalar):
if (false !== strpos($scalar, ',')) {
@trigger_error(self::getDeprecationMessage('Using the comma as a group separator for floats is deprecated since Symfony 3.2 and will be removed in 4.0.'), E_USER_DEPRECATED);
}
return (float) str_replace(array(',', '_'), '', $scalar);
return (float) str_replace('_', '', $scalar);
case Parser::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.
@ -783,53 +662,43 @@ class Inline
return (string) $scalar;
}
/**
* @param string $value
* @param int &$i
* @param int $flags
*
* @return null|string
*/
private static function parseTag($value, &$i, $flags)
private static function parseTag(string $value, int &$i, int $flags): ?string
{
if ('!' !== $value[$i]) {
return;
return null;
}
$tagLength = strcspn($value, " \t\n", $i + 1);
$tagLength = strcspn($value, " \t\n[]{},", $i + 1);
$tag = substr($value, $i + 1, $tagLength);
$nextOffset = $i + $tagLength + 1;
$nextOffset += strspn($value, ' ', $nextOffset);
// Is followed by a scalar
if ((!isset($value[$nextOffset]) || !\in_array($value[$nextOffset], array('[', '{'), true)) && 'tagged' !== $tag) {
// Manage non-whitelisted scalars in {@link self::evaluateScalar()}
return;
// Is followed by a scalar and is a built-in tag
if ('' !== $tag && (!isset($value[$nextOffset]) || !\in_array($value[$nextOffset], ['[', '{'], true)) && ('!' === $tag[0] || 'str' === $tag || 'php/const' === $tag || 'php/object' === $tag)) {
// Manage in {@link self::evaluateScalar()}
return null;
}
$i = $nextOffset;
// Built-in tags
if ($tag && '!' === $tag[0]) {
if ('' !== $tag && '!' === $tag[0]) {
throw new ParseException(sprintf('The built-in tag "!%s" is not implemented.', $tag), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
}
if (Yaml::PARSE_CUSTOM_TAGS & $flags) {
$i = $nextOffset;
if ('' !== $tag && !isset($value[$i])) {
throw new ParseException(sprintf('Missing value for tag "%s".', $tag), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
}
if ('' === $tag || Yaml::PARSE_CUSTOM_TAGS & $flags) {
return $tag;
}
throw new ParseException(sprintf('Tags support is not enabled. Enable the `Yaml::PARSE_CUSTOM_TAGS` flag to use "!%s".', $tag), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
throw new ParseException(sprintf('Tags support is not enabled. Enable the "Yaml::PARSE_CUSTOM_TAGS" flag to use "!%s".', $tag), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
}
/**
* @param string $scalar
*
* @return string
*
* @internal
*/
public static function evaluateBinaryScalar($scalar)
public static function evaluateBinaryScalar(string $scalar): string
{
$parsedBinaryData = self::parseScalar(preg_replace('/\s/', '', $scalar));
@ -844,7 +713,7 @@ class Inline
return base64_decode($parsedBinaryData, true);
}
private static function isBinaryString($value)
private static function isBinaryString(string $value)
{
return !preg_match('//u', $value) || preg_match('/[^\x00\x07-\x0d\x1B\x20-\xff]/', $value);
}
@ -856,7 +725,7 @@ class Inline
*
* @see http://www.yaml.org/spec/1.2/spec.html#id2761573
*/
private static function getTimestampRegex()
private static function getTimestampRegex(): string
{
return <<<EOF
~^
@ -876,26 +745,9 @@ EOF;
/**
* Gets a regex that matches a YAML number in hexadecimal notation.
*
* @return string
*/
private static function getHexRegex()
private static function getHexRegex(): string
{
return '~^0x[0-9a-f_]++$~i';
}
private static function getDeprecationMessage($message)
{
$message = rtrim($message, '.');
if (null !== self::$parsedFilename) {
$message .= ' in '.self::$parsedFilename;
}
if (-1 !== self::$parsedLineNumber) {
$message .= ' on line '.(self::$parsedLineNumber + 1);
}
return $message.'.';
}
}

View file

@ -1,4 +1,4 @@
Copyright (c) 2004-2018 Fabien Potencier
Copyright (c) 2004-2019 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

View file

@ -19,7 +19,7 @@ use Symfony\Component\Yaml\Tag\TaggedValue;
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since version 3.4
* @final
*/
class Parser
{
@ -29,27 +29,13 @@ class Parser
private $filename;
private $offset = 0;
private $totalNumberOfLines;
private $lines = array();
private $lines = [];
private $currentLineNb = -1;
private $currentLine = '';
private $refs = array();
private $skippedLineNumbers = array();
private $locallySkippedLineNumbers = array();
public function __construct()
{
if (\func_num_args() > 0) {
@trigger_error(sprintf('The constructor arguments $offset, $totalNumberOfLines, $skippedLineNumbers of %s are deprecated and will be removed in 4.0', self::class), E_USER_DEPRECATED);
$this->offset = func_get_arg(0);
if (\func_num_args() > 1) {
$this->totalNumberOfLines = func_get_arg(1);
}
if (\func_num_args() > 2) {
$this->skippedLineNumbers = func_get_arg(2);
}
}
}
private $refs = [];
private $skippedLineNumbers = [];
private $locallySkippedLineNumbers = [];
private $refsBeingParsed = [];
/**
* Parses a YAML file into a PHP value.
@ -61,7 +47,7 @@ class Parser
*
* @throws ParseException If the file could not be read or the YAML is not valid
*/
public function parseFile($filename, $flags = 0)
public function parseFile(string $filename, int $flags = 0)
{
if (!is_file($filename)) {
throw new ParseException(sprintf('File "%s" does not exist.', $filename));
@ -90,47 +76,15 @@ class Parser
*
* @throws ParseException If the YAML is not valid
*/
public function parse($value, $flags = 0)
public function parse(string $value, int $flags = 0)
{
if (\is_bool($flags)) {
@trigger_error('Passing a boolean flag to toggle exception handling is deprecated since Symfony 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 Symfony 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 Symfony 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 (Yaml::PARSE_KEYS_AS_STRINGS & $flags) {
@trigger_error('Using the Yaml::PARSE_KEYS_AS_STRINGS flag is deprecated since Symfony 3.4 as it will be removed in 4.0. Quote your keys when they are evaluable instead.', E_USER_DEPRECATED);
}
if (false === preg_match('//u', $value)) {
throw new ParseException('The YAML value does not appear to be valid UTF-8.', -1, null, $this->filename);
}
$this->refs = array();
$this->refs = [];
$mbEncoding = null;
$e = null;
$data = null;
if (2 /* MB_OVERLOAD_STRING */ & (int) ini_get('mbstring.func_overload')) {
$mbEncoding = mb_internal_encoding();
@ -139,34 +93,27 @@ class Parser
try {
$data = $this->doParse($value, $flags);
} catch (\Exception $e) {
} catch (\Throwable $e) {
}
if (null !== $mbEncoding) {
mb_internal_encoding($mbEncoding);
}
$this->lines = array();
$this->currentLine = '';
$this->refs = array();
$this->skippedLineNumbers = array();
$this->locallySkippedLineNumbers = array();
if (null !== $e) {
throw $e;
} finally {
if (null !== $mbEncoding) {
mb_internal_encoding($mbEncoding);
}
$this->lines = [];
$this->currentLine = '';
$this->refs = [];
$this->skippedLineNumbers = [];
$this->locallySkippedLineNumbers = [];
}
return $data;
}
private function doParse($value, $flags)
private function doParse(string $value, int $flags)
{
$this->currentLineNb = -1;
$this->currentLine = '';
$value = $this->cleanup($value);
$this->lines = explode("\n", $value);
$this->locallySkippedLineNumbers = array();
$this->locallySkippedLineNumbers = [];
if (null === $this->totalNumberOfLines) {
$this->totalNumberOfLines = \count($this->lines);
@ -176,7 +123,7 @@ class Parser
return null;
}
$data = array();
$data = [];
$context = null;
$allowOverwrite = false;
@ -204,24 +151,25 @@ class Parser
Inline::initialize($flags, $this->getRealCurrentLineNb(), $this->filename);
$isRef = $mergeNode = false;
if (self::preg_match('#^\-((?P<leadspaces>\s+)(?P<value>.+))?$#u', rtrim($this->currentLine), $values)) {
if ('-' === $this->currentLine[0] && self::preg_match('#^\-((?P<leadspaces>\s+)(?P<value>.+))?$#u', rtrim($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, $this->filename);
}
$context = 'sequence';
if (isset($values['value']) && self::preg_match('#^&(?P<ref>[^ ]+) *(?P<value>.*)#u', $values['value'], $matches)) {
if (isset($values['value']) && '&' === $values['value'][0] && self::preg_match('#^&(?P<ref>[^ ]+) *(?P<value>.*)#u', $values['value'], $matches)) {
$isRef = $matches['ref'];
$this->refsBeingParsed[] = $isRef;
$values['value'] = $matches['value'];
}
if (isset($values['value'][1]) && '?' === $values['value'][0] && ' ' === $values['value'][1]) {
@trigger_error($this->getDeprecationMessage('Starting an unquoted string with a question mark followed by a space is deprecated since Symfony 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.'), E_USER_DEPRECATED);
throw new ParseException('Complex mappings are not supported.', $this->getRealCurrentLineNb() + 1, $this->currentLine);
}
// array
if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#')) {
$data[] = $this->parseBlock($this->getRealCurrentLineNb() + 1, $this->getNextEmbedBlock(null, true), $flags);
$data[] = $this->parseBlock($this->getRealCurrentLineNb() + 1, $this->getNextEmbedBlock(null, true) ?? '', $flags);
} elseif (null !== $subTag = $this->getLineTag(ltrim($values['value'], ' '), $flags)) {
$data[] = new TaggedValue(
$subTag,
@ -244,10 +192,11 @@ class Parser
}
if ($isRef) {
$this->refs[$isRef] = end($data);
array_pop($this->refsBeingParsed);
}
} elseif (
self::preg_match('#^(?P<key>(?:![^\s]++\s++)?(?:'.Inline::REGEX_QUOTED_STRING.'|(?:!?!php/const:)?[^ \'"\[\{!].*?)) *\:(\s++(?P<value>.+))?$#u', rtrim($this->currentLine), $values)
&& (false === strpos($values['key'], ' #') || \in_array($values['key'][0], array('"', "'")))
&& (false === strpos($values['key'], ' #') || \in_array($values['key'][0], ['"', "'"]))
) {
if ($context && 'sequence' == $context) {
throw new ParseException('You cannot define a mapping item when in a sequence', $this->currentLineNb + 1, $this->currentLine, $this->filename);
@ -255,15 +204,7 @@ class Parser
$context = 'mapping';
try {
$i = 0;
$evaluateKey = !(Yaml::PARSE_KEYS_AS_STRINGS & $flags);
// constants in key will be evaluated anyway
if (isset($values['key'][0]) && '!' === $values['key'][0] && Yaml::PARSE_CONSTANT & $flags) {
$evaluateKey = true;
}
$key = Inline::parseScalar($values['key'], 0, null, $i, $evaluateKey);
$key = Inline::parseScalar($values['key']);
} catch (ParseException $e) {
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
$e->setSnippet($this->currentLine);
@ -272,8 +213,7 @@ class Parser
}
if (!\is_string($key) && !\is_int($key)) {
$keyType = is_numeric($key) ? 'numeric key' : 'non-string key';
@trigger_error($this->getDeprecationMessage(sprintf('Implicit casting of %s to string is deprecated since Symfony 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0. Quote your evaluable mapping keys instead.', $keyType)), E_USER_DEPRECATED);
throw new ParseException(sprintf('%s keys are not supported. Quote your evaluable mapping keys instead.', is_numeric($key) ? 'Numeric' : 'Non-string'), $this->getRealCurrentLineNb() + 1, $this->currentLine);
}
// Convert float keys to strings, to avoid being converted to integers by PHP
@ -281,12 +221,16 @@ class Parser
$key = (string) $key;
}
if ('<<' === $key && (!isset($values['value']) || !self::preg_match('#^&(?P<ref>[^ ]+)#u', $values['value'], $refMatches))) {
if ('<<' === $key && (!isset($values['value']) || '&' !== $values['value'][0] || !self::preg_match('#^&(?P<ref>[^ ]+)#u', $values['value'], $refMatches))) {
$mergeNode = true;
$allowOverwrite = true;
if (isset($values['value'][0]) && '*' === $values['value'][0]) {
$refName = substr(rtrim($values['value']), 1);
if (!array_key_exists($refName, $this->refs)) {
if (!\array_key_exists($refName, $this->refs)) {
if (false !== $pos = array_search($refName, $this->refsBeingParsed, true)) {
throw new ParseException(sprintf('Circular reference [%s, %s] detected for reference "%s".', implode(', ', \array_slice($this->refsBeingParsed, $pos)), $refName, $refName), $this->currentLineNb + 1, $this->currentLine, $this->filename);
}
throw new ParseException(sprintf('Reference "%s" does not exist.', $refName), $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
}
@ -338,8 +282,9 @@ class Parser
$data += $parsed; // array union
}
}
} elseif ('<<' !== $key && isset($values['value']) && self::preg_match('#^&(?P<ref>[^ ]++) *+(?P<value>.*)#u', $values['value'], $matches)) {
} elseif ('<<' !== $key && isset($values['value']) && '&' === $values['value'][0] && self::preg_match('#^&(?P<ref>[^ ]++) *+(?P<value>.*)#u', $values['value'], $matches)) {
$isRef = $matches['ref'];
$this->refsBeingParsed[] = $isRef;
$values['value'] = $matches['value'];
}
@ -359,9 +304,11 @@ class Parser
$data[$key] = null;
}
} else {
@trigger_error($this->getDeprecationMessage(sprintf('Duplicate key "%s" detected whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since Symfony 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key)), E_USER_DEPRECATED);
throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), $this->getRealCurrentLineNb() + 1, $this->currentLine);
}
} 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);
if ('<<' === $key) {
$this->refs[$refMatches['ref']] = $value;
@ -380,7 +327,7 @@ class Parser
$data[$key] = $value;
}
} else {
@trigger_error($this->getDeprecationMessage(sprintf('Duplicate key "%s" detected whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since Symfony 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key)), E_USER_DEPRECATED);
throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), $realCurrentLineNbKey + 1, $this->currentLine);
}
}
} else {
@ -390,11 +337,67 @@ class Parser
if ($allowOverwrite || !isset($data[$key])) {
$data[$key] = $value;
} else {
@trigger_error($this->getDeprecationMessage(sprintf('Duplicate key "%s" detected whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since Symfony 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key)), E_USER_DEPRECATED);
throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), $this->getRealCurrentLineNb() + 1, $this->currentLine);
}
}
if ($isRef) {
$this->refs[$isRef] = $data[$key];
array_pop($this->refsBeingParsed);
}
} elseif ('"' === $this->currentLine[0] || "'" === $this->currentLine[0]) {
if (null !== $context) {
throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
}
try {
return Inline::parse($this->parseQuotedString($this->currentLine), $flags, $this->refs);
} catch (ParseException $e) {
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
$e->setSnippet($this->currentLine);
throw $e;
}
} elseif ('{' === $this->currentLine[0]) {
if (null !== $context) {
throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
}
try {
$parsedMapping = Inline::parse($this->lexInlineMapping($this->currentLine), $flags, $this->refs);
while ($this->moveToNextLine()) {
if (!$this->isCurrentLineEmpty()) {
throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
}
}
return $parsedMapping;
} catch (ParseException $e) {
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
$e->setSnippet($this->currentLine);
throw $e;
}
} elseif ('[' === $this->currentLine[0]) {
if (null !== $context) {
throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
}
try {
$parsedSequence = Inline::parse($this->lexInlineSequence($this->currentLine), $flags, $this->refs);
while ($this->moveToNextLine()) {
if (!$this->isCurrentLineEmpty()) {
throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
}
}
return $parsedSequence;
} catch (ParseException $e) {
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
$e->setSnippet($this->currentLine);
throw $e;
}
} else {
// multiple documents are not supported
@ -403,7 +406,7 @@ class Parser
}
if ($deprecatedUsage = (isset($this->currentLine[1]) && '?' === $this->currentLine[0] && ' ' === $this->currentLine[1])) {
@trigger_error($this->getDeprecationMessage('Starting an unquoted string with a question mark followed by a space is deprecated since Symfony 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.'), E_USER_DEPRECATED);
throw new ParseException('Complex mappings are not supported.', $this->getRealCurrentLineNb() + 1, $this->currentLine);
}
// 1-liner optionally followed by newline(s)
@ -427,10 +430,18 @@ class Parser
$value = '';
foreach ($this->lines as $line) {
if ('' !== ltrim($line) && '#' === ltrim($line)[0]) {
continue;
}
// If the indentation is not consistent at offset 0, it is to be considered as a ParseError
if (0 === $this->offset && !$deprecatedUsage && isset($line[0]) && ' ' === $line[0]) {
throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename);
}
if (false !== strpos($line, ': ')) {
@trigger_error('Support for mapping keys in multi-line blocks is deprecated since Symfony 4.3 and will throw a ParseException in 5.0.', E_USER_DEPRECATED);
}
if ('' === trim($line)) {
$value .= "\n";
} elseif (!$previousLineWasNewline && !$previousLineWasTerminatedWithBackslash) {
@ -483,7 +494,7 @@ class Parser
return empty($data) ? null : $data;
}
private function parseBlock($offset, $yaml, $flags)
private function parseBlock(int $offset, string $yaml, int $flags)
{
$skippedLineNumbers = $this->skippedLineNumbers;
@ -500,6 +511,7 @@ class Parser
$parser->totalNumberOfLines = $this->totalNumberOfLines;
$parser->skippedLineNumbers = $skippedLineNumbers;
$parser->refs = &$this->refs;
$parser->refsBeingParsed = $this->refsBeingParsed;
return $parser->doParse($yaml, $flags);
}
@ -511,7 +523,7 @@ class Parser
*
* @return int The current line number
*/
public function getRealCurrentLineNb()
public function getRealCurrentLineNb(): int
{
$realCurrentLineNumber = $this->currentLineNb + $this->offset;
@ -531,7 +543,7 @@ class Parser
*
* @return int The current line indentation
*/
private function getCurrentLineIndentation()
private function getCurrentLineIndentation(): int
{
return \strlen($this->currentLine) - \strlen(ltrim($this->currentLine, ' '));
}
@ -539,24 +551,19 @@ class Parser
/**
* 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
* @param int|null $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)
private function getNextEmbedBlock(int $indentation = null, bool $inSequence = false): string
{
$oldLineIndentation = $this->getCurrentLineIndentation();
$blockScalarIndentations = array();
if ($this->isBlockScalarHeader()) {
$blockScalarIndentations[] = $oldLineIndentation;
}
if (!$this->moveToNextLine()) {
return;
return '';
}
if (null === $indentation) {
@ -591,7 +598,7 @@ class Parser
$newIndent = $indentation;
}
$data = array();
$data = [];
if ($this->getCurrentLineIndentation() >= $newIndent) {
$data[] = substr($this->currentLine, $newIndent);
} elseif ($this->isCurrentLineEmpty() || $this->isCurrentLineComment()) {
@ -599,7 +606,7 @@ class Parser
} else {
$this->moveToPreviousLine();
return;
return '';
}
if ($inSequence && $oldLineIndentation === $newIndent && isset($data[0][0]) && '-' === $data[0][0]) {
@ -607,35 +614,14 @@ class Parser
// and therefore no nested list or mapping
$this->moveToPreviousLine();
return;
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 >= $indent) {
unset($blockScalarIndentations[$key]);
}
}
}
if (empty($blockScalarIndentations) && !$this->isCurrentLineComment() && $this->isBlockScalarHeader()) {
$blockScalarIndentations[] = $indent;
}
$previousLineIndentation = $indent;
if ($isItUnindentedCollection && !$this->isCurrentLineEmpty() && !$this->isStringUnIndentedCollectionItem() && $newIndent === $indent) {
$this->moveToPreviousLine();
break;
@ -664,10 +650,8 @@ class Parser
/**
* Moves the parser to the next line.
*
* @return bool
*/
private function moveToNextLine()
private function moveToNextLine(): bool
{
if ($this->currentLineNb >= \count($this->lines) - 1) {
return false;
@ -680,10 +664,8 @@ class Parser
/**
* Moves the parser to the previous line.
*
* @return bool
*/
private function moveToPreviousLine()
private function moveToPreviousLine(): bool
{
if ($this->currentLineNb < 1) {
return false;
@ -705,7 +687,7 @@ class Parser
*
* @throws ParseException When reference does not exist
*/
private function parseValue($value, $flags, $context)
private function parseValue(string $value, int $flags, string $context)
{
if (0 === strpos($value, '*')) {
if (false !== $pos = strpos($value, '#')) {
@ -714,32 +696,40 @@ class Parser
$value = substr($value, 1);
}
if (!array_key_exists($value, $this->refs)) {
if (!\array_key_exists($value, $this->refs)) {
if (false !== $pos = array_search($value, $this->refsBeingParsed, true)) {
throw new ParseException(sprintf('Circular reference [%s, %s] detected for reference "%s".', implode(', ', \array_slice($this->refsBeingParsed, $pos)), $value, $value), $this->currentLineNb + 1, $this->currentLine, $this->filename);
}
throw new ParseException(sprintf('Reference "%s" does not exist.', $value), $this->currentLineNb + 1, $this->currentLine, $this->filename);
}
return $this->refs[$value];
}
if (self::preg_match('/^(?:'.self::TAG_PATTERN.' +)?'.self::BLOCK_SCALAR_HEADER_PATTERN.'$/', $value, $matches)) {
if (\in_array($value[0], ['!', '|', '>'], true) && self::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));
$data = $this->parseBlockScalar($matches['separator'], preg_replace('#\d+#', '', $modifiers), (int) abs((int) $modifiers));
if ('' !== $matches['tag']) {
if ('' !== $matches['tag'] && '!' !== $matches['tag']) {
if ('!!binary' === $matches['tag']) {
return Inline::evaluateBinaryScalar($data);
} elseif ('tagged' === $matches['tag']) {
return new TaggedValue(substr($matches['tag'], 1), $data);
} elseif ('!' !== $matches['tag']) {
@trigger_error($this->getDeprecationMessage(sprintf('Using the custom tag "%s" for the value "%s" is deprecated since Symfony 3.3. It will be replaced by an instance of %s in 4.0.', $matches['tag'], $data, TaggedValue::class)), E_USER_DEPRECATED);
}
return new TaggedValue(substr($matches['tag'], 1), $data);
}
return $data;
}
try {
if ('' !== $value && '{' === $value[0]) {
return Inline::parse($this->lexInlineMapping($value), $flags, $this->refs);
} elseif ('' !== $value && '[' === $value[0]) {
return Inline::parse($this->lexInlineSequence($value), $flags, $this->refs);
}
$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
@ -747,7 +737,7 @@ class Parser
return Inline::parse($value, $flags, $this->refs);
}
$lines = array();
$lines = [];
while ($this->moveToNextLine()) {
// unquoted strings end before the first unindented line
@ -801,10 +791,8 @@ class Parser
* @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)
private function parseBlockScalar(string $style, string $chomping = '', int $indentation = 0): string
{
$notEOF = $this->moveToNextLine();
if (!$notEOF) {
@ -812,7 +800,7 @@ class Parser
}
$isCurrentLineBlank = $this->isCurrentLineBlank();
$blockLines = array();
$blockLines = [];
// leading blank lines are consumed before determining indentation
while ($notEOF && $isCurrentLineBlank) {
@ -825,8 +813,10 @@ class Parser
// determine indentation if not specified
if (0 === $indentation) {
if (self::preg_match('/^ +/', $this->currentLine, $matches)) {
$indentation = \strlen($matches[0]);
$currentLineLength = \strlen($this->currentLine);
for ($i = 0; $i < $currentLineLength && ' ' === $this->currentLine[$i]; ++$i) {
++$indentation;
}
}
@ -911,7 +901,7 @@ class Parser
*
* @return bool Returns true if the next line is indented, false otherwise
*/
private function isNextLineIndented()
private function isNextLineIndented(): bool
{
$currentIndentation = $this->getCurrentLineIndentation();
$movements = 0;
@ -942,7 +932,7 @@ class Parser
*
* @return bool Returns true if the current line is empty or if it is a comment line, false otherwise
*/
private function isCurrentLineEmpty()
private function isCurrentLineEmpty(): bool
{
return $this->isCurrentLineBlank() || $this->isCurrentLineComment();
}
@ -952,7 +942,7 @@ class Parser
*
* @return bool Returns true if the current line is blank, false otherwise
*/
private function isCurrentLineBlank()
private function isCurrentLineBlank(): bool
{
return '' == trim($this->currentLine, ' ');
}
@ -962,7 +952,7 @@ class Parser
*
* @return bool Returns true if the current line is a comment line, false otherwise
*/
private function isCurrentLineComment()
private function isCurrentLineComment(): bool
{
//checking explicitly the first char of the trim is faster than loops or strpos
$ltrimmedLine = ltrim($this->currentLine, ' ');
@ -970,7 +960,7 @@ class Parser
return '' !== $ltrimmedLine && '#' === $ltrimmedLine[0];
}
private function isCurrentLineLastLineInDocument()
private function isCurrentLineLastLineInDocument(): bool
{
return ($this->offset + $this->currentLineNb) >= ($this->totalNumberOfLines - 1);
}
@ -982,9 +972,9 @@ class Parser
*
* @return string A cleaned up YAML string
*/
private function cleanup($value)
private function cleanup(string $value): string
{
$value = str_replace(array("\r\n", "\r"), "\n", $value);
$value = str_replace(["\r\n", "\r"], "\n", $value);
// strip YAML header
$count = 0;
@ -1018,7 +1008,7 @@ class Parser
*
* @return bool Returns true if the next line starts unindented collection, false otherwise
*/
private function isNextLineUnIndentedCollection()
private function isNextLineUnIndentedCollection(): bool
{
$currentIndentation = $this->getCurrentLineIndentation();
$movements = 0;
@ -1049,23 +1039,13 @@ class Parser
*
* @return bool Returns true if the string is un-indented collection item, false otherwise
*/
private function isStringUnIndentedCollectionItem()
private function isStringUnIndentedCollectionItem(): bool
{
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) self::preg_match('~'.self::BLOCK_SCALAR_HEADER_PATTERN.'$~', $this->currentLine);
}
/**
* A local wrapper for `preg_match` which will throw a ParseException if there
* A local wrapper for "preg_match" which will throw a ParseException if there
* is an internal error in the PCRE engine.
*
* This avoids us needing to check for "false" every time PCRE is used
@ -1077,7 +1057,7 @@ class Parser
*
* @internal
*/
public static function preg_match($pattern, $subject, &$matches = null, $flags = 0, $offset = 0)
public static function preg_match(string $pattern, string $subject, array &$matches = null, int $flags = 0, int $offset = 0): int
{
if (false === $ret = preg_match($pattern, $subject, $matches, $flags, $offset)) {
switch (preg_last_error()) {
@ -1109,10 +1089,10 @@ class Parser
/**
* Trim the tag on top of the value.
*
* Prevent values such as `!foo {quz: bar}` to be considered as
* Prevent values such as "!foo {quz: bar}" to be considered as
* a mapping block.
*/
private function trimTag($value)
private function trimTag(string $value): string
{
if ('!' === $value[0]) {
return ltrim(substr($value, 1, strcspn($value, " \r\n", 1)), ' ');
@ -1121,14 +1101,14 @@ class Parser
return $value;
}
private function getLineTag($value, $flags, $nextLineCheck = true)
private function getLineTag(string $value, int $flags, bool $nextLineCheck = true): ?string
{
if ('' === $value || '!' !== $value[0] || 1 !== self::preg_match('/^'.self::TAG_PATTERN.' *( +#.*)?$/', $value, $matches)) {
return;
return null;
}
if ($nextLineCheck && !$this->isNextLineIndented()) {
return;
return null;
}
$tag = substr($matches['tag'], 1);
@ -1142,19 +1122,124 @@ class Parser
return $tag;
}
throw new ParseException(sprintf('Tags support is not enabled. You must use the flag `Yaml::PARSE_CUSTOM_TAGS` to use "%s".', $matches['tag']), $this->getRealCurrentLineNb() + 1, $value, $this->filename);
throw new ParseException(sprintf('Tags support is not enabled. You must use the flag "Yaml::PARSE_CUSTOM_TAGS" to use "%s".', $matches['tag']), $this->getRealCurrentLineNb() + 1, $value, $this->filename);
}
private function getDeprecationMessage($message)
private function parseQuotedString(string $yaml): ?string
{
$message = rtrim($message, '.');
if (null !== $this->filename) {
$message .= ' in '.$this->filename;
if ('' === $yaml || ('"' !== $yaml[0] && "'" !== $yaml[0])) {
throw new \InvalidArgumentException(sprintf('"%s" is not a quoted string.', $yaml));
}
$message .= ' on line '.($this->getRealCurrentLineNb() + 1);
$lines = [$yaml];
return $message.'.';
while ($this->moveToNextLine()) {
$lines[] = $this->currentLine;
if (!$this->isCurrentLineEmpty() && $yaml[0] === $this->currentLine[-1]) {
break;
}
}
$value = '';
for ($i = 0, $linesCount = \count($lines), $previousLineWasNewline = false, $previousLineWasTerminatedWithBackslash = false; $i < $linesCount; ++$i) {
if ('' === trim($lines[$i])) {
$value .= "\n";
} elseif (!$previousLineWasNewline && !$previousLineWasTerminatedWithBackslash) {
$value .= ' ';
}
if ('' !== trim($lines[$i]) && '\\' === substr($lines[$i], -1)) {
$value .= ltrim(substr($lines[$i], 0, -1));
} elseif ('' !== trim($lines[$i])) {
$value .= trim($lines[$i]);
}
if ('' === trim($lines[$i])) {
$previousLineWasNewline = true;
$previousLineWasTerminatedWithBackslash = false;
} elseif ('\\' === substr($lines[$i], -1)) {
$previousLineWasNewline = false;
$previousLineWasTerminatedWithBackslash = true;
} else {
$previousLineWasNewline = false;
$previousLineWasTerminatedWithBackslash = false;
}
}
return $value;
for ($i = 1; isset($yaml[$i]) && $quotation !== $yaml[$i]; ++$i) {
}
// quoted single line string
if (isset($yaml[$i]) && $quotation === $yaml[$i]) {
return $yaml;
}
$lines = [$yaml];
while ($this->moveToNextLine()) {
for ($i = 1; isset($this->currentLine[$i]) && $quotation !== $this->currentLine[$i]; ++$i) {
}
$lines[] = trim($this->currentLine);
if (isset($this->currentLine[$i]) && $quotation === $this->currentLine[$i]) {
break;
}
}
}
private function lexInlineMapping(string $yaml): string
{
if ('' === $yaml || '{' !== $yaml[0]) {
throw new \InvalidArgumentException(sprintf('"%s" is not a sequence.', $yaml));
}
for ($i = 1; isset($yaml[$i]) && '}' !== $yaml[$i]; ++$i) {
}
if (isset($yaml[$i]) && '}' === $yaml[$i]) {
return $yaml;
}
$lines = [$yaml];
while ($this->moveToNextLine()) {
$lines[] = $this->currentLine;
}
return implode("\n", $lines);
}
private function lexInlineSequence(string $yaml): string
{
if ('' === $yaml || '[' !== $yaml[0]) {
throw new \InvalidArgumentException(sprintf('"%s" is not a sequence.', $yaml));
}
for ($i = 1; isset($yaml[$i]) && ']' !== $yaml[$i]; ++$i) {
}
if (isset($yaml[$i]) && ']' === $yaml[$i]) {
return $yaml;
}
$value = $yaml;
while ($this->moveToNextLine()) {
for ($i = 1; isset($this->currentLine[$i]) && ']' !== $this->currentLine[$i]; ++$i) {
}
$value .= trim($this->currentLine);
if (isset($this->currentLine[$i]) && ']' === $this->currentLine[$i]) {
break;
}
}
return $value;
}
}

View file

@ -20,27 +20,17 @@ final class TaggedValue
private $tag;
private $value;
/**
* @param string $tag
* @param mixed $value
*/
public function __construct($tag, $value)
public function __construct(string $tag, $value)
{
$this->tag = $tag;
$this->value = $value;
}
/**
* @return string
*/
public function getTag()
public function getTag(): string
{
return $this->tag;
}
/**
* @return mixed
*/
public function getValue()
{
return $this->value;

View file

@ -1,139 +0,0 @@
<?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\Command;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Component\Yaml\Command\LintCommand;
/**
* Tests the YamlLintCommand.
*
* @author Robin Chalas <robin.chalas@gmail.com>
*/
class LintCommandTest extends TestCase
{
private $files;
public function testLintCorrectFile()
{
$tester = $this->createCommandTester();
$filename = $this->createFile('foo: bar');
$ret = $tester->execute(array('filename' => $filename), array('verbosity' => OutputInterface::VERBOSITY_VERBOSE, 'decorated' => false));
$this->assertEquals(0, $ret, 'Returns 0 in case of success');
$this->assertRegExp('/^\/\/ OK in /', trim($tester->getDisplay()));
}
public function testLintIncorrectFile()
{
$incorrectContent = '
foo:
bar';
$tester = $this->createCommandTester();
$filename = $this->createFile($incorrectContent);
$ret = $tester->execute(array('filename' => $filename), array('decorated' => false));
$this->assertEquals(1, $ret, 'Returns 1 in case of error');
$this->assertContains('Unable to parse at line 3 (near "bar").', trim($tester->getDisplay()));
}
public function testConstantAsKey()
{
$yaml = <<<YAML
!php/const 'Symfony\Component\Yaml\Tests\Command\Foo::TEST': bar
YAML;
$ret = $this->createCommandTester()->execute(array('filename' => $this->createFile($yaml)), array('verbosity' => OutputInterface::VERBOSITY_VERBOSE, 'decorated' => false));
$this->assertSame(0, $ret, 'lint:yaml exits with code 0 in case of success');
}
public function testCustomTags()
{
$yaml = <<<YAML
foo: !my_tag {foo: bar}
YAML;
$ret = $this->createCommandTester()->execute(array('filename' => $this->createFile($yaml), '--parse-tags' => true), array('verbosity' => OutputInterface::VERBOSITY_VERBOSE, 'decorated' => false));
$this->assertSame(0, $ret, 'lint:yaml exits with code 0 in case of success');
}
public function testCustomTagsError()
{
$yaml = <<<YAML
foo: !my_tag {foo: bar}
YAML;
$ret = $this->createCommandTester()->execute(array('filename' => $this->createFile($yaml)), array('verbosity' => OutputInterface::VERBOSITY_VERBOSE, 'decorated' => false));
$this->assertSame(1, $ret, 'lint:yaml exits with code 1 in case of error');
}
/**
* @expectedException \RuntimeException
*/
public function testLintFileNotReadable()
{
$tester = $this->createCommandTester();
$filename = $this->createFile('');
unlink($filename);
$ret = $tester->execute(array('filename' => $filename), array('decorated' => false));
}
/**
* @return string Path to the new file
*/
private function createFile($content)
{
$filename = tempnam(sys_get_temp_dir().'/framework-yml-lint-test', 'sf-');
file_put_contents($filename, $content);
$this->files[] = $filename;
return $filename;
}
/**
* @return CommandTester
*/
protected function createCommandTester()
{
$application = new Application();
$application->add(new LintCommand());
$command = $application->find('lint:yaml');
return new CommandTester($command);
}
protected function setUp()
{
$this->files = array();
@mkdir(sys_get_temp_dir().'/framework-yml-lint-test');
}
protected function tearDown()
{
foreach ($this->files as $file) {
if (file_exists($file)) {
unlink($file);
}
}
rmdir(sys_get_temp_dir().'/framework-yml-lint-test');
}
}
class Foo
{
const TEST = 'foo';
}

View file

@ -1,495 +0,0 @@
<?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\Dumper;
use Symfony\Component\Yaml\Parser;
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);
}
public function testEmptyArray()
{
$dump = $this->dumper->dump(array());
$this->assertEquals('{ }', $dump);
$dump = $this->dumper->dump(array(), 0, 0, Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE);
$this->assertEquals('[]', $dump);
$dump = $this->dumper->dump(array(), 9, 0, Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE);
$this->assertEquals('[]', $dump);
$dump = $this->dumper->dump(new \ArrayObject(), 0, 0, Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE | Yaml::DUMP_OBJECT_AS_MAP);
$this->assertEquals('{ }', $dump);
$dump = $this->dumper->dump(new \stdClass(), 0, 0, Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE | Yaml::DUMP_OBJECT_AS_MAP);
$this->assertEquals('{ }', $dump);
}
/**
* @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 testDumpingArrayObjectInstancesRespectsInlineLevel()
{
$deep = new \ArrayObject(array('deep1' => 'd', 'deep2' => 'e'));
$inner = new \ArrayObject(array('inner1' => 'b', 'inner2' => 'c', 'inner3' => $deep));
$outer = new \ArrayObject(array('outer1' => 'a', 'outer2' => $inner));
$yaml = $this->dumper->dump($outer, 2, 0, Yaml::DUMP_OBJECT_AS_MAP);
$expected = <<<YAML
outer1: a
outer2:
inner1: b
inner2: c
inner3: { deep1: d, deep2: e }
YAML;
$this->assertSame($expected, $yaml);
}
public function testDumpingArrayObjectInstancesWithNumericKeysInlined()
{
$deep = new \ArrayObject(array('d', 'e'));
$inner = new \ArrayObject(array('b', 'c', $deep));
$outer = new \ArrayObject(array('a', $inner));
$yaml = $this->dumper->dump($outer, 0, 0, Yaml::DUMP_OBJECT_AS_MAP);
$expected = <<<YAML
{ 0: a, 1: { 0: b, 1: c, 2: { 0: d, 1: e } } }
YAML;
$this->assertSame($expected, $yaml);
}
public function testDumpingArrayObjectInstancesWithNumericKeysRespectsInlineLevel()
{
$deep = new \ArrayObject(array('d', 'e'));
$inner = new \ArrayObject(array('b', 'c', $deep));
$outer = new \ArrayObject(array('a', $inner));
$yaml = $this->dumper->dump($outer, 2, 0, Yaml::DUMP_OBJECT_AS_MAP);
$expected = <<<YAML
0: a
1:
0: b
1: c
2: { 0: d, 1: e }
YAML;
$this->assertEquals($expected, $yaml);
}
public function testDumpEmptyArrayObjectInstanceAsMap()
{
$this->assertSame('{ }', $this->dumper->dump(new \ArrayObject(), 2, 0, Yaml::DUMP_OBJECT_AS_MAP));
}
public function testDumpEmptyStdClassInstanceAsMap()
{
$this->assertSame('{ }', $this->dumper->dump(new \stdClass(), 2, 0, Yaml::DUMP_OBJECT_AS_MAP));
}
public function testDumpingStdClassInstancesRespectsInlineLevel()
{
$deep = new \stdClass();
$deep->deep1 = 'd';
$deep->deep2 = 'e';
$inner = new \stdClass();
$inner->inner1 = 'b';
$inner->inner2 = 'c';
$inner->inner3 = $deep;
$outer = new \stdClass();
$outer->outer1 = 'a';
$outer->outer2 = $inner;
$yaml = $this->dumper->dump($outer, 2, 0, Yaml::DUMP_OBJECT_AS_MAP);
$expected = <<<YAML
outer1: a
outer2:
inner1: b
inner2: c
inner3: { deep1: d, deep2: e }
YAML;
$this->assertSame($expected, $yaml);
}
public function testDumpMultiLineStringAsScalarBlock()
{
$data = array(
'data' => array(
'single_line' => 'foo bar baz',
'multi_line' => "foo\nline with trailing spaces:\n \nbar\ninteger like line:\n123456789\nempty line:\n\nbaz",
'multi_line_with_carriage_return' => "foo\nbar\r\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));
}
public function testDumpMultiLineStringAsScalarBlockWhenFirstLineHasLeadingSpace()
{
$data = array(
'data' => array(
'multi_line' => " the first line has leading spaces\nThe second line does not.",
),
);
$this->assertSame(file_get_contents(__DIR__.'/Fixtures/multiple_lines_as_literal_block_leading_space_in_first_line.yml'), $this->dumper->dump($data, 2, 0, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK));
}
public function testCarriageReturnIsMaintainedWhenDumpingAsMultiLineLiteralBlock()
{
$this->assertSame("- \"a\\r\\nb\\nc\"\n", $this->dumper->dump(array("a\r\nb\nc"), 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';
}

View file

@ -1,31 +0,0 @@
--- %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'))

View file

@ -1,202 +0,0 @@
--- %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
)
)

View file

@ -1,51 +0,0 @@
---
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',
)

View file

@ -1,85 +0,0 @@
--- %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"
)

View file

@ -1,25 +0,0 @@
---
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)

View file

@ -1,60 +0,0 @@
---
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))

View file

@ -1,176 +0,0 @@
--- %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"
)

View file

@ -1,45 +0,0 @@
--- %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: |
''

File diff suppressed because it is too large Load diff

View file

@ -1,266 +0,0 @@
--- %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: '&pound; me'
php: |
array(
'all my favorite symbols' => '#:!/%.)',
'a few i hate' => '&(*',
'why do i hate them?' => 'it\'s very hard to explain',
'entities' => '&pound; 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: 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 )

Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 B

View file

@ -1,11 +0,0 @@
--- %YAML:1.0
test: Miscellaneous
spec: 2.21
yaml: |
true: true
false: false
php: |
array(
'true' => true,
'false' => false,
)

View file

@ -1 +0,0 @@
value: <?php echo 1 + 2 + 3 ?>

View file

@ -1,155 +0,0 @@
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'
)

View file

@ -1,18 +0,0 @@
- escapedCharacters
- sfComments
- sfCompact
- sfTests
- sfObjects
- sfMergeKey
- sfQuotes
- YtsAnchorAlias
- YtsBasicTests
- YtsBlockMapping
- YtsDocumentSeparator
- YtsErrorTests
- YtsFlowCollections
- YtsFoldedScalars
- YtsNullsAndEmpties
- YtsSpecificationExamples
- YtsTypeTransfers
- unindentedCollections

View file

@ -1,23 +0,0 @@
--- %YAML:1.0
test: Miscellaneous
spec: 2.21
yaml: |
true: true
false: false
php: |
array(
1 => true,
0 => false,
)
---
test: Boolean
yaml: |
false: used as key
logical: true
answer: false
php: |
array(
false => 'used as key',
'logical' => true,
'answer' => false
)

View file

@ -1,2 +0,0 @@
- legacyBooleanMappingKeys
- legacyNullMappingKey

View file

@ -1,9 +0,0 @@
--- %YAML:1.0
test: Miscellaneous
spec: 2.21
yaml: |
null: ~
php: |
array(
'' => null,
)

View file

@ -1,14 +0,0 @@
data:
single_line: 'foo bar baz'
multi_line: |
foo
line with trailing spaces:
bar
integer like line:
123456789
empty line:
baz
multi_line_with_carriage_return: "foo\nbar\r\nbaz"
nested_inlined_multi_line_string: { inlined_multi_line: "foo\nbar\r\nempty line:\n\nbaz" }

View file

@ -1,3 +0,0 @@
- booleanMappingKeys
- numericMappingKeys
- nullMappingKey

View file

@ -1,9 +0,0 @@
--- %YAML:1.0
test: Miscellaneous
spec: 2.21
yaml: |
null: ~
php: |
array(
'null' => null,
)

View file

@ -1,23 +0,0 @@
--- %YAML:1.0
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: Integers as Map Keys
brief: >
An integer can be used as dictionary key.
yaml: |
1: one
2: two
3: three
php: |
array(
1 => 'one',
2 => 'two',
3 => 'three'
)

View file

@ -1,76 +0,0 @@
--- %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')

View file

@ -1,159 +0,0 @@
--- %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'
)
)
)

View file

@ -1,61 +0,0 @@
--- %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
bar_inline: {a: before, d: other, <<: *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
head_inline: &head_inline { <<: [ *foo , *dong , *foo2 ] }
recursive_inline: { <<: *head_inline, c: { <<: *foo2 } }
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'),
'bar_inline' => array('a' => 'before', 'd' => 'other', 'b' => 'new', 'c' => array('foo' => 'bar', 'bar' => 'foo'), 'e' => 'notnull', '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)),
'head_inline' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'e' => 'notnull', 'fi', 'fei', 'fo', 'fam'),
'recursive_inline' => array('a' => 'Steve', 'b' => 'Clark', 'c' => array('a' => 'Ballmer'), 'e' => 'notnull', 'fi', 'fei', 'fo', 'fam'),
)

View file

@ -1,11 +0,0 @@
--- %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')

View file

@ -1,33 +0,0 @@
--- %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',
),
)

View file

@ -1,140 +0,0 @@
--- %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: 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')

View file

@ -1,82 +0,0 @@
--- %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')))

View file

@ -1,816 +0,0 @@
<?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
{
protected function setUp()
{
Inline::initialize(0, 0);
}
/**
* @dataProvider getTestsForParse
*/
public function testParse($yaml, $value, $flags = 0)
{
$this->assertSame($value, Inline::parse($yaml, $flags), sprintf('::parse() converts an inline YAML to a PHP structure (%s)', $yaml));
}
/**
* @dataProvider getTestsForParseWithMapObjects
*/
public function testParseWithMapObjects($yaml, $value, $flags = Yaml::PARSE_OBJECT_FOR_MAP)
{
$actual = Inline::parse($yaml, $flags);
$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)),
array('!php/const NULL', null),
);
}
/**
* @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
* @expectedDeprecation The !php/const: tag to indicate dumped PHP constants is deprecated since Symfony 3.4 and will be removed in 4.0. Use the !php/const (without the colon) tag instead on line 1.
* @dataProvider getTestsForParseLegacyPhpConstants
*/
public function testDeprecatedConstantTag($yaml, $expectedValue)
{
$this->assertSame($expectedValue, Inline::parse($yaml, Yaml::PARSE_CONSTANT));
}
public function getTestsForParseLegacyPhpConstants()
{
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)),
array('!php/const:NULL', null),
);
}
/**
* @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, $parseFlags = 0)
{
$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), $parseFlags), '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 after an unquoted mapping key that is not followed by an indication character (i.e. " ", ",", "[", "]", "{", "}") is deprecated since Symfony 3.2 and will throw a ParseException in 4.0 on line 1.
* 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 at line 1.
*/
public function testParseUnquotedAsterisk()
{
Inline::parse('{ foo: * }');
}
/**
* @expectedException \Symfony\Component\Yaml\Exception\ParseException
* @expectedExceptionMessage A reference must contain at least one character at line 1.
*/
public function testParseUnquotedAsteriskFollowedByAComment()
{
Inline::parse('{ foo: * #foo }');
}
/**
* @dataProvider getReservedIndicators
*/
public function testParseUnquotedScalarStartingWithReservedIndicator($indicator)
{
if (method_exists($this, 'expectExceptionMessage')) {
$this->expectException(ParseException::class);
$this->expectExceptionMessage(sprintf('cannot start a plain scalar; you need to quote the scalar at line 1 (near "%sfoo ").', $indicator));
} else {
$this->setExpectedException(ParseException::class, sprintf('cannot start a plain scalar; you need to quote the scalar at line 1 (near "%sfoo ").', $indicator));
}
Inline::parse(sprintf('{ foo: %sfoo }', $indicator));
}
public function getReservedIndicators()
{
return array(array('@'), array('`'));
}
/**
* @dataProvider getScalarIndicators
*/
public function testParseUnquotedScalarStartingWithScalarIndicator($indicator)
{
if (method_exists($this, 'expectExceptionMessage')) {
$this->expectException(ParseException::class);
$this->expectExceptionMessage(sprintf('cannot start a plain scalar; you need to quote the scalar at line 1 (near "%sfoo ").', $indicator));
} else {
$this->setExpectedException(ParseException::class, sprintf('cannot start a plain scalar; you need to quote the scalar at line 1 (near "%sfoo ").', $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 on line 1.
* 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')),
array('{"foo:bar": "baz"}', array('foo:bar' => 'baz')),
array('{"foo":"bar"}', array('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), Yaml::PARSE_OBJECT_FOR_MAP),
array('{ foo : bar, bar : foo, "false" : false, "null" : null, integer : 12 }', (object) array('foo' => 'bar', 'bar' => 'foo', 'false' => false, 'null' => null, 'integer' => 12), Yaml::PARSE_OBJECT_FOR_MAP),
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')),
array('{"foo:bar": "baz"}', (object) array('foo:bar' => 'baz')),
array('{"foo":"bar"}', (object) array('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} at line 1.
*/
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']);
}
/**
* @group legacy
* @expectedDeprecation Omitting the key of a mapping is deprecated and will throw a ParseException in 4.0 on line 1.
*/
public function testOmittedMappingKeyIsParsedAsColon()
{
$this->assertSame(array(':' => 'foo'), Inline::parse('{: foo}'));
}
/**
* @dataProvider getTestsForNullValues
*/
public function testParseMissingMappingValueAsNull($yaml, $expected)
{
$this->assertSame($expected, Inline::parse($yaml));
}
public function getTestsForNullValues()
{
return array(
'null before closing curly brace' => array('{foo:}', array('foo' => null)),
'null before comma' => array('{foo:, bar: baz}', array('foo' => null, 'bar' => 'baz')),
);
}
public function testTheEmptyStringIsAValidMappingKey()
{
$this->assertSame(array('' => 'foo'), Inline::parse('{ "": foo }'));
}
/**
* @group legacy
* @expectedDeprecation Implicit casting of incompatible mapping keys to strings is deprecated since Symfony 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0. Quote your evaluable mapping keys instead on line 1.
* @dataProvider getNotPhpCompatibleMappingKeyData
*/
public function testImplicitStringCastingOfMappingKeysIsDeprecated($yaml, $expected)
{
$this->assertSame($expected, Inline::parse($yaml));
}
/**
* @group legacy
* @expectedDeprecation Using the Yaml::PARSE_KEYS_AS_STRINGS flag is deprecated since Symfony 3.4 as it will be removed in 4.0. Quote your keys when they are evaluable instead.
* @expectedDeprecation Implicit casting of incompatible mapping keys to strings is deprecated since Symfony 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0. Quote your evaluable mapping keys instead on line 1.
* @dataProvider getNotPhpCompatibleMappingKeyData
*/
public function testExplicitStringCastingOfMappingKeys($yaml, $expected)
{
$this->assertSame($expected, Yaml::parse($yaml, Yaml::PARSE_KEYS_AS_STRINGS));
}
public function getNotPhpCompatibleMappingKeyData()
{
return array(
'boolean-true' => array('{true: "foo"}', array('true' => 'foo')),
'boolean-false' => array('{false: "foo"}', array('false' => 'foo')),
'null' => array('{null: "foo"}', array('null' => 'foo')),
'float' => array('{0.25: "foo"}', array('0.25' => 'foo')),
);
}
/**
* @group legacy
* @expectedDeprecation Support for the !str tag is deprecated since Symfony 3.4. Use the !!str tag instead on line 1.
*/
public function testDeprecatedStrTag()
{
$this->assertSame(array('foo' => 'bar'), Inline::parse('{ foo: !str bar }'));
}
/**
* @expectedException \Symfony\Component\Yaml\Exception\ParseException
* @expectedExceptionMessage Unexpected end of line, expected one of ",}" at line 1 (near "{abc: 'def'").
*/
public function testUnfinishedInlineMap()
{
Inline::parse("{abc: 'def'");
}
}

View file

@ -1,34 +0,0 @@
<?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());
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,44 +0,0 @@
<?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);
}
}

View file

@ -35,7 +35,7 @@ class Unescaper
*
* @return string The unescaped string
*/
public function unescapeSingleQuotedString($value)
public function unescapeSingleQuotedString(string $value): string
{
return str_replace('\'\'', '\'', $value);
}
@ -47,7 +47,7 @@ class Unescaper
*
* @return string The unescaped string
*/
public function unescapeDoubleQuotedString($value)
public function unescapeDoubleQuotedString(string $value): string
{
$callback = function ($match) {
return $this->unescapeCharacter($match[0]);
@ -64,7 +64,7 @@ class Unescaper
*
* @return string The unescaped character
*/
private function unescapeCharacter($value)
private function unescapeCharacter(string $value): string
{
switch ($value[1]) {
case '0':
@ -120,12 +120,8 @@ class Unescaper
/**
* 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)
private static function utf8chr(int $c): string
{
if (0x80 > $c %= 0x200000) {
return \chr($c);

View file

@ -18,7 +18,7 @@ use Symfony\Component\Yaml\Exception\ParseException;
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since version 3.4
* @final
*/
class Yaml
{
@ -33,20 +33,15 @@ class Yaml
const PARSE_CONSTANT = 256;
const PARSE_CUSTOM_TAGS = 512;
const DUMP_EMPTY_ARRAY_AS_SEQUENCE = 1024;
/**
* @deprecated since version 3.4, to be removed in 4.0. Quote your evaluable keys instead.
*/
const PARSE_KEYS_AS_STRINGS = 2048;
const DUMP_NULL_AS_TILDE = 2048;
/**
* Parses a YAML file into a PHP value.
*
* Usage:
* <code>
* $array = Yaml::parseFile('config.yml');
* print_r($array);
* </code>
* Usage:
*
* $array = Yaml::parseFile('config.yml');
* print_r($array);
*
* @param string $filename The path to the YAML file to be parsed
* @param int $flags A bit field of PARSE_* constants to customize the YAML parser behavior
@ -55,7 +50,7 @@ class Yaml
*
* @throws ParseException If the file could not be read or the YAML is not valid
*/
public static function parseFile($filename, $flags = 0)
public static function parseFile(string $filename, int $flags = 0)
{
$yaml = new Parser();
@ -78,34 +73,8 @@ class Yaml
*
* @throws ParseException If the YAML is not valid
*/
public static function parse($input, $flags = 0)
public static function parse(string $input, int $flags = 0)
{
if (\is_bool($flags)) {
@trigger_error('Passing a boolean flag to toggle exception handling is deprecated since Symfony 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 Symfony 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 Symfony 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);
@ -124,26 +93,8 @@ class Yaml
*
* @return string A YAML string representing the original PHP value
*/
public static function dump($input, $inline = 2, $indent = 4, $flags = 0)
public static function dump($input, int $inline = 2, int $indent = 4, int $flags = 0): string
{
if (\is_bool($flags)) {
@trigger_error('Passing a boolean flag to toggle exception handling is deprecated since Symfony 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 Symfony 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);

View file

@ -16,11 +16,11 @@
}
],
"require": {
"php": "^5.5.9|>=7.0.8",
"php": "^7.1.3",
"symfony/polyfill-ctype": "~1.8"
},
"require-dev": {
"symfony/console": "~3.4|~4.0"
"symfony/console": "^3.4|^4.0|^5.0"
},
"conflict": {
"symfony/console": "<3.4"
@ -37,7 +37,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "3.4-dev"
"dev-master": "4.4-dev"
}
}
}

View file

@ -1,30 +0,0 @@
<?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"
failOnRisky="true"
failOnWarning="true"
>
<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>