From 18ea43740160f5a615abd908f6bf682a0b0cdfab Mon Sep 17 00:00:00 2001 From: Roman Paska Date: Mon, 13 Jan 2020 23:31:02 +0200 Subject: [PATCH 1/6] Improve line matching mechanism by introducing line ids This change allows for matching lines that were edited. --- src/Comments.php | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/src/Comments.php b/src/Comments.php index bff0a35..6a49284 100644 --- a/src/Comments.php +++ b/src/Comments.php @@ -27,6 +27,7 @@ class Comments protected $hasStored; protected $headComments; protected $accumulated; + protected $lineIds; protected $stored; protected $endComments; @@ -35,6 +36,7 @@ public function __construct() $this->hasStored = false; $this->headComments = false; $this->accumulated = []; + $this->lineIds = []; $this->stored = []; $this->endComments = []; } @@ -137,6 +139,7 @@ protected function accumulate($line) */ protected function storeAccumulated($line) { + // Remember that we called storeAccumulated at least once $this->hasStored = true; @@ -150,12 +153,41 @@ protected function storeAccumulated($line) return; } if (!empty($this->accumulated)) { - // $this->stored saves a stack of accumulated results. - $this->stored[$line][] = $this->accumulated; + $lineId = $this->getLineId($line, true); + $this->stored[$lineId][] = $this->accumulated; $this->accumulated = []; } } + /** + * Generates unique line id based on the key it contains. + * + * @param string $line + * @param bool $isCollecting + */ + protected function getLineId($line, $isCollecting = true) + { + list($id) = explode(':', $line, 2); + + if ($isCollecting) { + if (isset($this->lineIds[$id])) { + $this->lineIds[$id][] = end($this->lineIds[$id]) + 1; + } + else { + $this->lineIds[$id] = [1]; + } + + return end($this->lineIds[$id]) . '|' . $id; + } + + if (isset($this->lineIds[$id])) { + return array_shift($this->lineIds[$id]) . '|' . $id; + } + else { + return '1|' . $id; + } + } + /** * Check to see if the provided line has any associated comments. * @@ -163,13 +195,14 @@ protected function storeAccumulated($line) */ protected function find($line) { - if (!isset($this->stored[$line]) || empty($this->stored[$line])) { + $lineId = $this->getLineId($line, false); + if (!isset($this->stored[$lineId]) || empty($this->stored[$lineId])) { return []; } // The stored result is a stack of accumulated comments. Pop // one off; if more remain, they will be attached to the next // line with the same value. - return array_shift($this->stored[$line]); + return array_shift($this->stored[$lineId]); } /** From 6403f888f223a2a2895ba8172efd399f98060b9b Mon Sep 17 00:00:00 2001 From: Roman Paska Date: Mon, 13 Jan 2020 23:38:17 +0200 Subject: [PATCH 2/6] Address PHPCS errors --- src/Comments.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Comments.php b/src/Comments.php index 6a49284..631548d 100644 --- a/src/Comments.php +++ b/src/Comments.php @@ -172,8 +172,7 @@ protected function getLineId($line, $isCollecting = true) if ($isCollecting) { if (isset($this->lineIds[$id])) { $this->lineIds[$id][] = end($this->lineIds[$id]) + 1; - } - else { + } else { $this->lineIds[$id] = [1]; } @@ -182,8 +181,7 @@ protected function getLineId($line, $isCollecting = true) if (isset($this->lineIds[$id])) { return array_shift($this->lineIds[$id]) . '|' . $id; - } - else { + } else { return '1|' . $id; } } From c5829db68350d87d8ed3b92cedc811937296e799 Mon Sep 17 00:00:00 2001 From: Roman Paska Date: Mon, 13 Jan 2020 23:57:25 +0200 Subject: [PATCH 3/6] Add test coverage for the new line matching mechanism --- tests/TestComments.php | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tests/TestComments.php b/tests/TestComments.php index 139fbc3..36cefca 100644 --- a/tests/TestComments.php +++ b/tests/TestComments.php @@ -49,6 +49,42 @@ function commentTestData() two: EOT; + $duplicate_comments = <<< 'EOT' +# Top comments +top: + # Top one + one: + # Top two + two: +# Bottom comments +bottom: + # Bottom one + one: + # Bottom two + two: two +EOT; + + $duplicate_altered_without_comments = <<< 'EOT' +top: + one: + two: 2 +bottom: + one: 1 +EOT; + + $duplicate_altered_with_comments = <<< 'EOT' +# Top comments +top: + # Top one + one: + # Top two + two: 2 +# Bottom comments +bottom: + # Bottom one + one: 1 +EOT; + $travis_yaml_with_comments = <<< 'EOT' dist: trusty language: php @@ -126,6 +162,7 @@ function commentTestData() return [ [ $simple_yaml, $simple_yaml_reordered, $simple_yaml_expected, ], [ $indented_comments, $indented_without_comments, $indented_comments, ], + [ $duplicate_comments, $duplicate_altered_without_comments, $duplicate_altered_with_comments, ], [ $travis_yaml_with_comments, $travis_yaml_without_comments, $travis_yaml_with_comments ], ]; } From 626452ac24dd50792d380e9d156a7cee18116e08 Mon Sep 17 00:00:00 2001 From: Roman Paska Date: Mon, 20 Jan 2020 10:46:29 +0200 Subject: [PATCH 4/6] Ensure that passed args are valid YAML --- tests/TestComments.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/TestComments.php b/tests/TestComments.php index 36cefca..fe8b25d 100644 --- a/tests/TestComments.php +++ b/tests/TestComments.php @@ -1,6 +1,8 @@ parse($arg); + } + // Second step: collect comments from original document and inject them into result. $commentManager = new Comments(); From d500e1a92f9891f9b2ac6123568949e4bd705932 Mon Sep 17 00:00:00 2001 From: Roman Paska Date: Mon, 20 Jan 2020 11:44:02 +0200 Subject: [PATCH 5/6] Add detailed inline comments to the getLineId() method --- src/Comments.php | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/src/Comments.php b/src/Comments.php index 631548d..11afcb0 100644 --- a/src/Comments.php +++ b/src/Comments.php @@ -17,10 +17,6 @@ * * If the resulting yaml file contents are reordered, comments may * become mis-ordered (attached to the wrong element). - * - * Comments that appear before sections of yaml that are edited may - * be inadvertantly lost. It is recommended to always place comments - * immediately before identifier lines (i.e. "foo:"). */ class Comments { @@ -160,7 +156,34 @@ protected function storeAccumulated($line) } /** - * Generates unique line id based on the key it contains. + * Generates unique line id based on the key it contains. It allows + * to reattach comments to the edited yaml sections. + * + * For example, lets take a look at the following yaml: + * + * # Top comments + * top: + * # Top one + * one: + * # Top two + * two: two + * # Bottom comments + * bottom: + * # Bottom one + * one: + * # Bottom two + * two: 2 + * + * This method generates ids based on keys (discarding values). + * Additionally, duplicating keys are taken into account as well. + * The following ids will be generated: + * + * 1|top + * 1| one + * 1| two + * 1|bottom + * 2| one + * 2| two * * @param string $line * @param bool $isCollecting From 4d4df53cb2233903b53fd0894a72ae41a06f3311 Mon Sep 17 00:00:00 2001 From: Roman Paska Date: Fri, 13 Mar 2020 13:06:24 +0200 Subject: [PATCH 6/6] Bring back code comments regarding possibility of the data loss --- src/Comments.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Comments.php b/src/Comments.php index 11afcb0..19cf57c 100644 --- a/src/Comments.php +++ b/src/Comments.php @@ -17,6 +17,10 @@ * * If the resulting yaml file contents are reordered, comments may * become mis-ordered (attached to the wrong element). + * + * Comments that appear before sections of yaml that are edited may + * be inadvertantly lost. It is recommended to always place comments + * immediately before identifier lines (i.e. "foo:"). */ class Comments {