@@ -216,6 +216,14 @@ private function updateData(array $newData)
216216 continue ;
217217 }
218218
219+ if (
220+ $ this ->isMultilineString ($ newVal )
221+ && rtrim ($ currentVal , "\n" ) !== $ currentVal
222+ && rtrim ($ newVal , "\n" ) === $ newVal
223+ ) {
224+ $ newVal .= "\n" ;
225+ }
226+
219227 // 3b) value DID change
220228 $ this ->log (sprintf ('updating value to {%s} ' , \is_array ($ newVal ) ? '<array> ' : $ newVal ));
221229 $ this ->changeValueInYaml ($ newVal );
@@ -449,8 +457,15 @@ private function changeValueInYaml($value)
449457
450458 $ endValuePosition = $ this ->findEndPositionOfValue ($ originalVal );
451459
452- $ newYamlValue = $ this ->convertToYaml ($ value );
453- if (!\is_array ($ originalVal ) && \is_array ($ value )) {
460+ $ isMultilineValue = null !== $ this ->findPositionOfMultilineCharInLine ($ this ->currentPosition );
461+ $ originalValEndsWithNewLine = $ isMultilineValue ? rtrim ($ originalVal , "\n" ) !== $ originalVal : false ;
462+
463+ // In case of multiline, $value is converted as plain string like "Foo\nBar"
464+ // We need to keep it "as is"
465+ $ newYamlValue = $ isMultilineValue ? rtrim ($ value , "\n" ) : $ this ->convertToYaml ($ value );
466+ if ((!\is_array ($ originalVal ) && \is_array ($ value )) ||
467+ ($ this ->isMultilineString ($ originalVal ) && $ this ->isMultilineString ($ value ))
468+ ) {
454469 // we're converting from a scalar to a (multiline) array
455470 // this means we need to break onto the next line
456471
@@ -468,8 +483,14 @@ private function changeValueInYaml($value)
468483 ++$ newPosition ;
469484 }
470485
486+ if ($ isMultilineValue ) {
487+ // strlen(" |")
488+ $ newPosition -= 2 ;
489+ }
490+
471491 $ newContents = substr ($ this ->contents , 0 , $ this ->currentPosition )
472- .$ newYamlValue
492+ .($ isMultilineValue ? ' | ' : '' )
493+ .($ originalValEndsWithNewLine ? rtrim ($ newYamlValue , ' ' ) : $ newYamlValue )
473494 /*
474495 * If the next line is a comment, this means we probably had
475496 * a structure that looks like this:
@@ -771,16 +792,26 @@ private function findEndPositionOfValue($value, $offset = null)
771792 }
772793
773794 if (is_scalar ($ value ) || null === $ value ) {
795+ $ offset = null === $ offset ? $ this ->currentPosition : $ offset ;
796+
774797 if (\is_bool ($ value )) {
775798 // (?i) & (?-i) opens/closes case insensitive match
776799 $ pattern = sprintf ('(?i)%s(?-i) ' , $ value ? 'true ' : 'false ' );
777800 } elseif (null === $ value ) {
778801 $ pattern = '(~|NULL|null|\n) ' ;
779802 } else {
780- $ pattern = sprintf ('\'?"?%s \'?"? ' , preg_quote ($ value , '# ' ));
781- }
803+ // Multiline value ends with \n.
804+ // If we remove this character, the next property will ne merged with this value
805+ $ quotedValue = preg_quote (rtrim ($ value , "\n" ), '# ' );
806+ $ patternValue = $ quotedValue ;
807+
808+ // Iterates until we find a new line char or we reach end of file
809+ if ($ this ->findPositionOfMultilineCharInLine ($ offset )) {
810+ $ patternValue = str_replace (["\r\n" , "\n" ], '\r?\n\s* ' , $ quotedValue );
811+ }
782812
783- $ offset = null === $ offset ? $ this ->currentPosition : $ offset ;
813+ $ pattern = sprintf ('\'?"?%s \'?"? ' , $ patternValue );
814+ }
784815
785816 // a value like "foo:" can simply end a file
786817 // this means the value is null
@@ -1164,7 +1195,31 @@ private function indentMultilineYamlArray(string $yaml): string
11641195 // also need to be indented artificially by the same amount
11651196 $ yaml = str_replace ("\n" , "\n" .$ this ->getCurrentIndentation (), $ yaml );
11661197
1198+ if ($ this ->isMultilineString ($ yaml )) {
1199+ // Remove extra indentation in case of blank line in multiline string
1200+ $ yaml = str_replace ("\n" .$ this ->getCurrentIndentation ()."\n" , "\n\n" , $ yaml );
1201+ }
1202+
11671203 // now indent this level
11681204 return $ this ->getCurrentIndentation ().$ yaml ;
11691205 }
1206+
1207+ private function findPositionOfMultilineCharInLine (int $ position ): ?int
1208+ {
1209+ $ cursor = $ position ;
1210+ while (!$ this ->isCharLineBreak ($ currentChar = substr ($ this ->contents , $ cursor + 1 , 1 )) && !$ this ->isEOF ($ cursor )) {
1211+ if ('| ' === $ currentChar ) {
1212+ return $ cursor ;
1213+ }
1214+
1215+ ++$ cursor ;
1216+ }
1217+
1218+ return null ;
1219+ }
1220+
1221+ private function isMultilineString ($ value ): bool
1222+ {
1223+ return \is_string ($ value ) && false !== strpos ($ value , "\n" );
1224+ }
11701225}
0 commit comments