Skip to content
Closed
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
25 changes: 22 additions & 3 deletions src/Symfony/Component/Yaml/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,10 @@ private function parseValue(string $value, int $flags, string $context): mixed
default:
$lines = [];

$realCurrentLineNb = $this->getRealCurrentLineNb();

$hasColonInHead = str_contains($value, ': ');

while ($this->moveToNextLine()) {
if ($this->isCurrentLineBlank()) {
$lines[] = '';
Expand Down Expand Up @@ -799,14 +803,29 @@ private function parseValue(string $value, int $flags, string $context): mixed
$parsedValue = Inline::parse($value, $flags, $this->refs);

if ('mapping' === $context && \is_string($parsedValue) && '"' !== $value[0] && "'" !== $value[0] && '[' !== $value[0] && '{' !== $value[0] && '!' !== $value[0] && str_contains($parsedValue, ': ')) {
throw new ParseException('A colon cannot be used in an unquoted mapping value.', $this->getRealCurrentLineNb() + 1, $value, $this->filename);
$line = $realCurrentLineNb + 1;
$snippet = $value;

if (!$hasColonInHead) {
foreach ($lines as $i => $lineContent) {
if (str_contains($lineContent, ': ')) {
$line += $i + 1;
$snippet = $lineContent;
break;
}
}
}

throw new ParseException('A colon cannot be used in an unquoted mapping value.', $line, $snippet, $this->filename);
}

return $parsedValue;
}
} catch (ParseException $e) {
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
$e->setSnippet($this->currentLine);
if (-1 === $e->getParsedLine()) {
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
$e->setSnippet($this->currentLine);
}

throw $e;
}
Expand Down
105 changes: 51 additions & 54 deletions src/Symfony/Component/Yaml/Tests/ParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1315,8 +1315,7 @@ public static function getCommentLikeStringInScalarBlockData()
</body>

footer # comment3
EOT
,
EOT,
],
],
];
Expand All @@ -1343,25 +1342,22 @@ public static function getCommentLikeStringInScalarBlockData()
# bar
baz

EOT
,
EOT,
'collection' => [
[
'one' => <<<'EOT'
foo
# bar
baz

EOT
,
EOT,
],
[
'two' => <<<'EOT'
foo
# bar
baz
EOT
,
EOT,
],
],
];
Expand Down Expand Up @@ -1425,8 +1421,7 @@ public function testBlankLinesAreParsedAsNewLinesInFoldedBlocks()
'test' => <<<'EOT'
<h2>A heading</h2>
<ul> <li>a list</li> <li>may be a good example</li> </ul>
EOT
,
EOT,
],
$this->parser->parse($yaml)
);
Expand All @@ -1452,8 +1447,7 @@ public function testAdditionallyIndentedLinesAreParsedAsNewLinesInFoldedBlocks()
<li>a list</li>
<li>may be a good example</li>
</ul>
EOT
,
EOT,
],
$this->parser->parse($yaml)
);
Expand Down Expand Up @@ -1510,32 +1504,28 @@ public static function getInvalidBinaryData()
<<<'EOT'
data: !!binary |
SGVsbG8d29ybGQ=
EOT
,
EOT,
'/The normalized base64 encoded data \(data without whitespace characters\) length must be a multiple of four \(\d+ bytes given\)/',
],
'invalid characters in block scalar' => [
<<<'EOT'
data: !!binary |
SGVsbG8#d29ybGQ=
EOT
,
EOT,
'/The base64 encoded data \(.*\) contains invalid characters/',
],
'too many equals characters in block scalar' => [
<<<'EOT'
data: !!binary |
SGVsbG8gd29yb===
EOT
,
EOT,
'/The base64 encoded data \(.*\) contains invalid characters/',
],
'misplaced equals character in block scalar' => [
<<<'EOT'
data: !!binary |
SGVsbG8gd29ybG=Q
EOT
,
EOT,
'/The base64 encoded data \(.*\) contains invalid characters/',
],
];
Expand Down Expand Up @@ -1909,8 +1899,7 @@ public static function escapedQuotationCharactersInQuotedStrings()
- message: 'No emails received before timeout - Address: ''test@testemail.company.com''
Keyword: ''Your Order confirmation'' ttl: 50'
outcome: failed
YAML
,
YAML,
[
'entries' => [
[
Expand All @@ -1926,8 +1915,7 @@ public static function escapedQuotationCharactersInQuotedStrings()
- message: "No emails received before timeout - Address: \"test@testemail.company.com\"
Keyword: \"Your Order confirmation\" ttl: 50"
outcome: failed
YAML
,
YAML,
[
'entries' => [
[
Expand Down Expand Up @@ -2035,8 +2023,7 @@ public static function inlineNotationSpanningMultipleLinesProvider(): array
'foo': 'bar',
'bar': 'baz'
}
YAML
,
YAML,
],
'mapping with unquoted strings and values' => [
['foo' => 'bar', 'bar' => 'baz'],
Expand All @@ -2045,8 +2032,7 @@ public static function inlineNotationSpanningMultipleLinesProvider(): array
foo: bar,
bar: baz
}
YAML
,
YAML,
],
'sequence' => [
['foo', 'bar'],
Expand All @@ -2055,8 +2041,7 @@ public static function inlineNotationSpanningMultipleLinesProvider(): array
'foo',
'bar'
]
YAML
,
YAML,
],
'sequence with unquoted items' => [
['foo', 'bar'],
Expand All @@ -2065,8 +2050,7 @@ public static function inlineNotationSpanningMultipleLinesProvider(): array
foo,
bar
]
YAML
,
YAML,
],
'nested mapping terminating at end of line' => [
[
Expand All @@ -2077,8 +2061,7 @@ public static function inlineNotationSpanningMultipleLinesProvider(): array
<<<YAML
{ foo: { bar: foobar }
}
YAML
,
YAML,
],
'nested sequence terminating at end of line' => [
[
Expand Down Expand Up @@ -2112,8 +2095,7 @@ public static function inlineNotationSpanningMultipleLinesProvider(): array
'foo': ['bar', 'foobar'],
'bar': ['baz']
}
YAML
,
YAML,
],
'sequence spanning multiple lines nested in mapping' => [
[
Expand All @@ -2128,8 +2110,7 @@ public static function inlineNotationSpanningMultipleLinesProvider(): array
bar,
baz
]
YAML
,
YAML,
],
'sequence spanning multiple lines nested in mapping with a following mapping' => [
[
Expand Down Expand Up @@ -2162,8 +2143,7 @@ public static function inlineNotationSpanningMultipleLinesProvider(): array
bar,
baz
]]
YAML
,
YAML,
],
'nested sequence nested in mapping starting on the following line' => [
[
Expand All @@ -2181,8 +2161,7 @@ public static function inlineNotationSpanningMultipleLinesProvider(): array
bar,
baz
]]
YAML
,
YAML,
],
'mapping nested in sequence' => [
['foo', ['bar' => 'baz']],
Expand All @@ -2193,8 +2172,7 @@ public static function inlineNotationSpanningMultipleLinesProvider(): array
'bar': 'baz'
}
]
YAML
,
YAML,
],
'mapping spanning multiple lines nested in sequence' => [
[
Expand All @@ -2208,8 +2186,7 @@ public static function inlineNotationSpanningMultipleLinesProvider(): array
foo: bar,
bar: baz
}
YAML
,
YAML,
],
'nested mapping nested in sequence starting on the same line' => [
[
Expand All @@ -2226,8 +2203,7 @@ public static function inlineNotationSpanningMultipleLinesProvider(): array
},
bar: baz
}
YAML
,
YAML,
],
'nested mapping nested in sequence starting on the following line' => [
[
Expand All @@ -2245,26 +2221,23 @@ public static function inlineNotationSpanningMultipleLinesProvider(): array
},
bar: baz
}
YAML
,
YAML,
],
'single quoted multi-line string' => [
"foo\nbar",
<<<YAML
'foo

bar'
YAML
,
YAML,
],
'double quoted multi-line string' => [
"foo\nbar",
<<<YAML
'foo

bar'
YAML
,
YAML,
],
'single-quoted multi-line mapping value' => [
['foo' => "bar\nbaz"],
Expand Down Expand Up @@ -2666,6 +2639,30 @@ public function testParserCleansUpReferencesBetweenRuns()
$this->parser->parse($yaml);
}

/**
* @see https://github.com/symfony/symfony/issues/62581
*/
public function testParseExceptionLineNumberForUnquotedMappingValueWithIndentedContent()
{
$yaml = <<<YAML
en:
NONAMESPACE: Include Entity without Namespace
Invalid: Foo
About: 'About us'
- Invalid
YAML;

try {
$this->parser->parse($yaml);
$this->fail('A ParseException should have been thrown.');
} catch (ParseException $e) {
$this->assertSame(4, $e->getParsedLine(), 'The line number is incorrect.');
$this->assertStringContainsString('A colon cannot be used in an unquoted mapping value', $e->getMessage());
$this->assertStringContainsString('at line 4', $e->getMessage());
$this->assertStringContainsString("About: 'About us'", $e->getSnippet(), 'The snippet is incorrect.');
}
}

public function testPhpConstantTagMappingKey()
{
$yaml = <<<YAML
Expand Down