diff --git a/src/Symfony/Component/Yaml/Dumper.php b/src/Symfony/Component/Yaml/Dumper.php index 679d533cb77aa..99346aa1edd90 100644 --- a/src/Symfony/Component/Yaml/Dumper.php +++ b/src/Symfony/Component/Yaml/Dumper.php @@ -69,9 +69,7 @@ public function dump($input, int $inline = 0, int $indent = 0, int $flags = 0): } if (Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK & $flags && \is_string($value) && false !== strpos($value, "\n") && false === strpos($value, "\r")) { - // 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, 0, 1)) ? (string) $this->indentation : ''; + $blockIndentationIndicator = $this->getBlockIndentationIndicator($value); if (isset($value[-2]) && "\n" === $value[-2] && "\n" === $value[-1]) { $blockChompingIndicator = '+'; @@ -98,9 +96,7 @@ public function dump($input, int $inline = 0, int $indent = 0, int $flags = 0): $output .= sprintf('%s%s !%s', $prefix, $dumpAsMap ? Inline::dump($key, $flags).':' : '-', $value->getTag()); if (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 : ''; + $blockIndentationIndicator = $this->getBlockIndentationIndicator($value->getValue()); $output .= sprintf(' |%s', $blockIndentationIndicator); foreach (explode("\n", $value->getValue()) as $row) { @@ -145,9 +141,7 @@ private function dumpTaggedValue(TaggedValue $value, int $inline, int $indent, i $output = sprintf('%s!%s', $prefix ? $prefix.' ' : '', $value->getTag()); if (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 : ''; + $blockIndentationIndicator = $this->getBlockIndentationIndicator($value->getValue()); $output .= sprintf(' |%s', $blockIndentationIndicator); foreach (explode("\n", $value->getValue()) as $row) { @@ -163,4 +157,20 @@ private function dumpTaggedValue(TaggedValue $value, int $inline, int $indent, i return $output."\n".$this->dump($value->getValue(), $inline - 1, $indent, $flags); } + + private function getBlockIndentationIndicator(string $value): string + { + $lines = explode("\n", $value); + + // If the first line (that is neither empty nor contains only spaces) + // starts with a space character, the spec requires a block indentation indicator + // http://www.yaml.org/spec/1.2/spec.html#id2793979 + foreach ($lines as $line) { + if ('' !== trim($line, ' ')) { + return (' ' === substr($line, 0, 1)) ? (string) $this->indentation : ''; + } + } + + return ''; + } } diff --git a/src/Symfony/Component/Yaml/Tests/DumperTest.php b/src/Symfony/Component/Yaml/Tests/DumperTest.php index 721b04caab2ee..5a96a6c41af99 100644 --- a/src/Symfony/Component/Yaml/Tests/DumperTest.php +++ b/src/Symfony/Component/Yaml/Tests/DumperTest.php @@ -710,6 +710,42 @@ public function testDumpMultiLineStringAsScalarBlockWhenFirstLineHasLeadingSpace $this->assertSame($data, $this->parser->parse($yml)); } + public function testDumpMultiLineStringAsScalarBlockWhenFirstLineIsEmptyAndSecondLineHasLeadingSpace() + { + $data = [ + 'data' => [ + 'multi_line' => "\n the second line has leading spaces\nThe third line does not.", + ], + ]; + + $expected = "data:\n multi_line: |4-\n\n the second line has leading spaces\n The third line does not."; + + $yml = $this->dumper->dump($data, 2, 0, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK); + $this->assertSame($expected, $yml); + $this->assertSame($data, $this->parser->parse($yml)); + } + + public function testDumpMultiLineStringAsScalarBlockWhenFirstLineHasOnlySpaces() + { + $data = [ + 'data' => [ + 'multi_line' => " \nthe second line\nThe third line.", + ], + ]; + + $expectedData = [ + 'data' => [ + 'multi_line' => "\nthe second line\nThe third line.", + ], + ]; + + $expectedYml = "data:\n multi_line: |-\n \n the second line\n The third line."; + + $yml = $this->dumper->dump($data, 2, 0, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK); + $this->assertSame($expectedYml, $yml); + $this->assertSame($expectedData, $this->parser->parse($yml)); + } + public function testCarriageReturnFollowedByNewlineIsMaintainedWhenDumpingAsMultiLineLiteralBlock() { $data = ["a\r\nb\nc"];