8000 [Yaml] expose references detected in inline notation structures by xabbuh · Pull Request #40923 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[Yaml] expose references detected in inline notation structures #40923

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 17 additions & 7 deletions src/Symfony/Component/Yaml/Inline.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public static function initialize(int $flags, int $parsedLineNumber = null, stri
*
* @throws ParseException
*/
public static function parse(string $value = null, int $flags = 0, array $references = [])
public static function parse(string $value = null, int $flags = 0, array &$references = [])
{
self::initialize($flags);

Expand Down Expand Up @@ -267,7 +267,7 @@ private static function dumpNull(int $flags): string
*
* @throws ParseException When malformed inline YAML string is parsed
*/
public static function parseScalar(string $scalar, int $flags = 0, array $delimiters = null, int &$i = 0, bool $evaluate = true, array $references = [])
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], ['"', "'"])) {
// quoted scalar
Expand Down Expand Up @@ -343,7 +343,7 @@ private static function parseQuotedScalar(string $scalar, int &$i): string
*
* @throws ParseException When malformed inline YAML string is parsed
*/
private static function parseSequence(string $sequence, int $flags, int &$i = 0, array $references = []): array
private static function parseSequence(string $sequence, int $flags, int &$i = 0, array &$references = []): array
{
$output = [];
$len = \strlen($sequence);
Expand Down Expand Up @@ -385,6 +385,11 @@ private static function parseSequence(string $sequence, int $flags, int &$i = 0,
}
}

if (\is_string($value) && '' !== $value && '&' === $value[0] && Parser::preg_match(Parser::REFERENCE_PATTERN, $value, $matches)) {
$references[$matches['ref']] = $matches['value'];
$value = $matches['value'];
}

--$i;
}

Expand All @@ -407,7 +412,7 @@ private static function parseSequence(string $sequence, int $flags, int &$i = 0,
*
* @throws ParseException When malformed inline YAML string is parsed
*/
private static function parseMapping(string $mapping, int $flags, int &$i = 0, array $references = [])
private static function parseMapping(string $mapping, int $flags, int &$i = 0, array &$references = [])
{
$output = [];
$len = \strlen($mapping);
Expand All @@ -433,14 +438,14 @@ private static function parseMapping(string $mapping, int $flags, int &$i = 0, a
// key
$offsetBeforeKeyParsing = $i;
$isKeyQuoted = \in_array($mapping[$i], ['"', "'"], true);
$key = self::parseScalar($mapping, $flags, [':', ' '], $i, false, []);
$key = self::parseScalar($mapping, $flags, [':', ' '], $i, false);

if ($offsetBeforeKeyParsing === $i) {
throw new ParseException('Missing mapping key.', self::$parsedLineNumber + 1, $mapping);
}

if ('!php/const' === $key) {
$key .= ' '.self::parseScalar($mapping, $flags, [':'], $i, false, []);
$key .= ' '.self::parseScalar($mapping, $flags, [':'], $i, false);
$key = self::evaluateScalar($key, $flags);
}

Expand Down Expand Up @@ -522,6 +527,11 @@ private static function parseMapping(string $mapping, int $flags, int &$i = 0, a
if ('<<' === $key) {
$output += $value;
} elseif ($allowOverwrite || !isset($output[$key])) {
if (\is_string($value) && '' !== $value && '&' === $value[0] && Parser::preg_match(Parser::REFERENCE_PATTERN, $value, $matches)) {
$references[$matches['ref']] = $matches['value'];
$value = $matches['value'];
}

if (null !== $tag) {
$output[$key] = new TaggedValue($tag, $value);
} else {
Expand All @@ -548,7 +558,7 @@ private static function parseMapping(string $mapping, int $flags, int &$i = 0, a
*
* @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(string $scalar, int $flags, array $references = [])
private static function evaluateScalar(string $scalar, int $flags, array &$references = [])
{
$scalar = trim($scalar);
$scalarLower = strtolower($scalar);
Expand Down
5 changes: 8000 3 additions & 2 deletions src/Symfony/Component/Yaml/Parser.php
8000
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class Parser
{
public const TAG_PATTERN = '(?P<tag>![\w!.\/:-]+)';
public const BLOCK_SCALAR_HEADER_PATTERN = '(?P<separator>\||>)(?P<modifiers>\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P<comments> +#.*)?';
public const REFERENCE_PATTERN = '#^&(?P<ref>[^ ]++) *+(?P<value>.*)#u';

private $filename;
private $offset = 0;
Expand Down Expand Up @@ -158,7 +159,7 @@ private function doParse(string $value, int $flags)
}
$context = 'sequence';

if (isset($values['value']) && '&' === $values['value'][0] && self::preg_match('#^&(?P<ref>[^ ]+) *(?P<value>.*)#u', $values['value'], $matches)) {
if (isset($values['value']) && '&' === $values['value'][0] && self::preg_match(self::REFERENCE_PATTERN, $values['value'], $matches)) {
$isRef = $matches['ref'];
$this->refsBeingParsed[] = $isRef;
$values['value'] = $matches['value'];
Expand Down Expand Up @@ -296,7 +297,7 @@ private function doParse(string $value, int $flags)
$data += $parsed; // array union
}
}
} elseif ('<<' !== $key && isset($values['value']) && '&' === $values['value'][0] && self::preg_match('#^&(?P<ref>[^ ]++) *+(?P<value>.*)#u', $values['value'], $matches)) {
} elseif ('<<' !== $key && isset($values['value']) && '&' === $values['value'][0] && self::preg_match(self::REFERENCE_PATTERN, $values['value'], $matches)) {
$isRef = $matches['ref'];
$this->refsBeingParsed[] = $isRef;
$values['value'] = $matches['value'];
Expand Down
6 changes: 4 additions & 2 deletions src/Symfony/Component/Yaml/Tests/InlineTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,8 @@ public function testParseScalarWithCorrectlyQuotedStringShouldReturnString()
*/
public function testParseReferences($yaml, $expected)
{
$this->assertSame($expected, Inline::parse($yaml, 0, ['var' => 'var-value']));
$references = ['var' => 'var-value'];
$this->assertSame($expected, Inline::parse($yaml, 0, $references));
}

public function getDataForParseReferences()
Expand All @@ -211,7 +212,8 @@ public function testParseMapReferenceInSequence()
'b' => 'Clark',
'c' => 'Brian',
];
$this->assertSame([$foo], Inline::parse('[*foo]', 0, ['foo' => $foo]));
$references = ['foo' => $foo];
$this->assertSame([$foo], Inline::parse('[*foo]', 0, $references));
}

public function testParseUnquotedAsterisk()
Expand Down
8 changes: 8 additions & 0 deletions src/Symfony/Component/Yaml/Tests/ParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1073,6 +1073,10 @@ public function testReferenceResolvingInInlineStrings()
'map' => ['key' => 'var-value'],
'list_in_map' => ['key' => ['var-value']],
'map_in_map' => ['foo' => ['bar' => 'var-value']],
'foo' => ['bar' => 'baz'],
'bar' => ['foo' => 'baz'],
'baz' => ['foo'],
'foobar' => ['foo'],
], Yaml::parse(<<<'EOF'
var: &var var-value
scalar: *var
Expand All @@ -1083,6 +1087,10 @@ public function testReferenceResolvingInInlineStrings()
map: { key: *var }
list_in_map: { key: [*var] }
map_in_map: { foo: { bar: *var } }
foo: { bar: &baz baz }
bar: { foo: *baz }
baz: [ &foo foo ]
foobar: [ *foo ]
EOF
));
}
Expand Down
0