Skip to content

Commit ee7e823

Browse files
committed
Add test case for multiline string
1 parent 0b5fd0e commit ee7e823

7 files changed

+150
-7
lines changed

src/Util/YamlSourceManipulator.php

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -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
}

tests/Util/YamlSourceManipulatorTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ private function getYamlDataTests()
5858
foreach ($finder as $file) {
5959
list($source, $changeCode, $expected) = explode('===', $file->getContents());
6060

61-
$data = Yaml::parse($source);
61+
// Multiline string ends with an \n
62+
$data = Yaml::parse(trim($source, "\n"));
6263
eval($changeCode);
6364

6465
yield $file->getFilename() => [
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
nelmio_api_doc:
2+
documentation:
3+
info:
4+
description: |
5+
Multiline string
6+
Second line
7+
===
8+
$data['nelmio_api_doc']['documentation']['info']['description'] = "Multiline string\nSecond line\nThird line";
9+
===
10+
nelmio_api_doc:
11+
documentation:
12+
info:
13+
description: |
14+
Multiline string
15+
Second line
16+
Third line
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
nelmio_api_doc:
2+
documentation:
3+
info:
4+
description: |
5+
Multiline string
6+
Second line
7+
foo: bar
8+
===
9+
$data['nelmio_api_doc']['documentation']['info']['description'] = "Multiline string\nSecond line\nThird line\n";
10+
===
11+
nelmio_api_doc:
12+
documentation:
13+
info:
14+
description: |
15+
Multiline string
16+
Second line
17+
Third line
18+
foo: bar
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
nelmio_api_doc:
2+
documentation:
3+
info:
4+
description: |
5+
Multiline string
6+
Second line
7+
Third line
8+
foo: bar
9+
===
10+
$data['nelmio_api_doc']['documentation']['info']['description'] = "Multiline string\nSecond line\n";
11+
===
12+
nelmio_api_doc:
13+
documentation:
14+
info:
15+
description: |
16+
Multiline string
17+
Second line
18+
foo: bar
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
nelmio_api_doc:
2+
documentation:
3+
info:
4+
description: |
5+
Multiline string
6+
7+
Second line
8+
foo: bar
9+
===
10+
$data['nelmio_api_doc']['documentation']['info']['description'] = "Multiline string\n\nSecond line\nThird line\n";
11+
===
12+
nelmio_api_doc:
13+
documentation:
14+
info:
15+
description: |
16+
Multiline string
17+
18+
Second line
19+
Third line
20+
foo: bar
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
nelmio_api_doc:
2+
documentation:
3+
info:
4+
description: |
5+
Multiline string
6+
Second line
7+
===
8+
9+
===
10+
nelmio_api_doc:
11+
documentation:
12+
info:
13+
description: |
14+
Multiline string
15+
Second line

0 commit comments

Comments
 (0)