diff --git a/src/Symfony/Component/Yaml/Dumper.php b/src/Symfony/Component/Yaml/Dumper.php index dcb104ccff065..8472f4c45b294 100644 --- a/src/Symfony/Component/Yaml/Dumper.php +++ b/src/Symfony/Component/Yaml/Dumper.php @@ -97,14 +97,27 @@ public function dump($input, int $inline = 0, int $indent = 0, int $flags = 0): if ($value instanceof TaggedValue) { $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 (Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK & $flags && \is_string($value->getValue()) && false !== strpos($value->getValue(), "\n") && false === strpos($value->getValue(), "\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->getValue(), 0, 1)) ? (string) $this->indentation : ''; - $output .= sprintf(' |%s', $blockIndentationIndicator); + + if (isset($value->getValue()[-2]) && "\n" === $value->getValue()[-2] && "\n" === $value->getValue()[-1]) { + $blockChompingIndicator = '+'; + } elseif ("\n" === $value->getValue()[-1]) { + $blockChompingIndicator = ''; + } else { + $blockChompingIndicator = '-'; + } + + $output .= sprintf(' |%s%s', $blockIndentationIndicator, $blockChompingIndicator); foreach (explode("\n", $value->getValue()) as $row) { - $output .= sprintf("\n%s%s%s", $prefix, str_repeat(' ', $this->indentation), $row); + if ('' === $row) { + $output .= "\n"; + } else { + $output .= sprintf("\n%s%s%s", $prefix, str_repeat(' ', $this->indentation), $row); + } } continue; diff --git a/src/Symfony/Component/Yaml/Tests/DumperTest.php b/src/Symfony/Component/Yaml/Tests/DumperTest.php index 6329aec86ccff..2c27a8d5dae49 100644 --- a/src/Symfony/Component/Yaml/Tests/DumperTest.php +++ b/src/Symfony/Component/Yaml/Tests/DumperTest.php @@ -494,7 +494,7 @@ public function testDumpingMultiLineStringAsScalarBlockTaggedValue() $data = [ 'foo' => new TaggedValue('bar', "foo\nline with trailing spaces:\n \nbar\ninteger like line:\n123456789\nempty line:\n\nbaz"), ]; - $expected = "foo: !bar |\n". + $expected = "foo: !bar |-\n". " foo\n". " line with trailing spaces:\n". " \n". @@ -502,7 +502,7 @@ public function testDumpingMultiLineStringAsScalarBlockTaggedValue() " integer like line:\n". " 123456789\n". " empty line:\n". - " \n". + "\n". ' baz'; $this->assertSame($expected, $this->dumper->dump($data, 2, 0, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK)); @@ -553,6 +553,21 @@ public function testCarriageReturnFollowedByNewlineIsMaintainedWhenDumpingAsMult $this->assertSame("- \"a\\r\\nb\\nc\"\n", $this->dumper->dump(["a\r\nb\nc"], 2, 0, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK)); } + public function testCarriageReturnNotFollowedByNewlineIsPreservedWhenDumpingTaggedValueAsMultiLineLiteralBlock() + { + $expected = <<<'YAML' +parent: + foo: !my-tag "bar\n\rbaz: qux" + +YAML; + + $this->assertSame($expected, $this->dumper->dump([ + 'parent' => [ + 'foo' => new TaggedValue('my-tag', "bar\n\rbaz: qux"), + ], + ], 4, 0, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK)); + } + public function testCarriageReturnNotFollowedByNewlineIsPreservedWhenDumpingAsMultiLineLiteralBlock() { $expected = <<<'YAML' @@ -580,38 +595,51 @@ public function testNoExtraTrailingNewlineWhenDumpingAsMultiLineLiteralBlock() $this->assertSame($data, Yaml::parse($yaml)); } - public function testDumpTrailingNewlineInMultiLineLiteralBlocks() + public function testDumpTrailingNewlineInMultiLineLiteralBlocksForTaggedValues() { $data = [ - 'clip 1' => "one\ntwo\n", - 'clip 2' => "one\ntwo\n", - 'keep 1' => "one\ntwo\n", - 'keep 2' => "one\ntwo\n\n", - 'strip 1' => "one\ntwo", - 'strip 2' => "one\ntwo", + 'clip 1' => new TaggedValue('my-tag', "one\ntwo\n"), + 'keep 1' => new TaggedValue('my-tag', "one\ntwo\n\n"), + 'strip 1' => new TaggedValue('my-tag', "one\ntwo"), ]; $yaml = $this->dumper->dump($data, 2, 0, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK); $expected = <<assertSame($expected, $yaml); + } + + public function testDumpTrailingNewlineInMultiLineLiteralBlocks() + { + $data = [ + 'clip 1' => "one\ntwo\n", + 'keep 1' => "one\ntwo\n\n", + 'strip 1' => "one\ntwo", + ]; + $yaml = $this->dumper->dump($data, 2, 0, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK); + + $expected = <<assertSame($expected, $yaml);