-
Notifications
You must be signed in to change notification settings - Fork 77
Prevent YamlEditor.remove from affecting existing block scalars
#2240
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces a significant and well-reasoned refactoring to how YAML block collection entries are removed, aiming to prevent unintended effects on block scalars. The new removeBlockCollectionEntry function is a great addition for centralizing this complex logic. The changes are thoroughly commented and include relevant test cases. I've identified a couple of areas for improvement in the new utility functions to enhance correctness and clarity.
01a4b9d to
bf49685
Compare
Package publishing
Documentation at https://github.com/dart-lang/ecosystem/wiki/Publishing-automation. |
PR HealthLicense Headers ✔️
All source files should start with a license header. Unrelated files missing license headers
This check can be disabled by tagging the PR with API leaks ✔️The following packages contain symbols visible in the public API, but not exported by the library. Export these symbols or remove them from your publicly visible API.
This check can be disabled by tagging the PR with Breaking changes ✔️
This check can be disabled by tagging the PR with
Coverage
|
| File | Coverage |
|---|---|
| pkgs/yaml_edit/lib/src/equality.dart | 💔 88 % ⬇️ 13 % |
| pkgs/yaml_edit/lib/src/list_mutations.dart | 💔 99 % ⬇️ 0 % |
| pkgs/yaml_edit/lib/src/map_mutations.dart | 💚 100 % |
| pkgs/yaml_edit/lib/src/utils.dart | 💔 98 % ⬇️ 0 % |
This check for test coverage is informational (issues shown here will not fail the PR).
This check can be disabled by tagging the PR with skip-coverage-check.
Changelog Entry ❗
| Package | Changed Files |
|---|---|
| package:yaml_edit | pkgs/yaml_edit/lib/src/equality.dart pkgs/yaml_edit/lib/src/list_mutations.dart pkgs/yaml_edit/lib/src/map_mutations.dart pkgs/yaml_edit/lib/src/utils.dart |
Changes to files need to be accounted for in their respective changelogs.
This check can be disabled by tagging the PR with skip-changelog-check.
111d8e6 to
3d394f6
Compare
|
Does this preserve non-indented trailing comments? |
|
Yes. |
|
@dart-lang/dart-pub-team I believe this needs a review :) |
jonasfj
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, it took long to do a review.
WOW, there is a lot of corner cases here.
This is really hard to follow. To be fair, it's also solving a LOT of cases!
I'm not saying there is much better way to do this.
It's just really complicated to keep even half the cases that this handles in your head at the same time 🤣
My comments are mostly just nits, nothing substantial.
I've reviewed the code, and tried to follow it (managed to understand some of it).
But unless I start playing with making examples and tweaking everything I don't think I can confidently claim I understand all the corner cases -- I'm simply not that smart 🤣
I also assume that you've spent a non-trivial amount of time figuring out all this! It's very impressive!
I think we should land it. Even if there is a few nits, of course it'd be great to fix them, but it's just nits.
@sigurdm, would you mind giving it a superficial read through, if you have no major concerns I suggest we ship it.
pkgs/yaml_edit/lib/src/utils.dart
Outdated
| end -= lineEnding == '\r\n' ? 2 : 1; | ||
| } | ||
|
|
||
| replacement = isBlockList ? '[]' : '{}'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: but I'd suggest returning early.
| replacement = isBlockList ? '[]' : '{}'; | |
| return SourceEdit(start, end - start, isBlockList ? '[]' : '{}'); |
Similarly, in the if (!isLastEntry) { block, then you remove at-least one level of nesting.
Not sure that makes what happens easier to understand, but I can see that it's complex for a reason.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense. It was intentional. Returning once looked cleaner. Will fix this to reduce the nesting.
pkgs/yaml_edit/lib/src/utils.dart
Outdated
| final (:nearestLineEnding, :nextNodeColStart) = nextBlockNodeInfo(); | ||
| final trueEndOffset = end - 1; | ||
|
|
||
| /// Make compact only if we are pointing to same line break from different |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit. technically these are not documentation comment, just comments so // would be more accurate than ///.
Not that this is important.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😁 force of habit. No problem.
pkgs/yaml_edit/test/utils_test.dart
Outdated
| expect( | ||
| indexOfCompactChar( | ||
| yaml, | ||
| mapKeys.elementAt(1).span.start.offset, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| mapKeys.elementAt(1).span.start.offset, | |
| mapKeys[1].span.start.offset, |
Aren't you just taking the second element of a list? I guess maybe do .toList()
| yaml, | ||
| ) as YamlMap) | ||
| .nodes | ||
| .keys |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| .keys | |
| .keys | |
| .toList() |
Just to avoid elementAt(1) which doesn't make the code less cryptic 🤣
|
I'd note that more tests would always be appreciated. Especially, the kinds of tests we have in: Because even if we don't care to manually write the .golden files, and even if reviews of these are limited. The self-test logic we have that decodes the YAML and compares it with the expected result does offer a lot of value. |
Certainly! I remember. I just needed the go-ahead (review) to edit the existing failing tests that are affected by this change. Will work on this and include more edge cases. |
Absolutely, if there are existing test cases affected by this change, we should update them. Then we can review if those changes are problematic or not, my guess is that we should be willing to eat a few more comments and be willing to accept slightly less pretty output in exchange for fewer bugs! |
| target-key: value # Comment | ||
| # Comment | ||
| next: value |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's also have a test that non-indented comments are kept
key: >+
folded with keep chomping
target-key: value # Comment
# This comment should stay
Comment viewnext: value
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. This was flaky for maps. Fixed it in the latest changes.
sigurdm
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see no red flags in the code, but agree the code is highly nontrivial, and I'm not sure I follow all the details.
Yeah, we need to fix all existing tests, and that would also make it easier to see the impact of the change when reviewing.
* Refactor `_removeFromBlockList` and `_removeFromBlockMap` and remove dangling line breaks which may affect how block scalars are intepreted by the `package: yaml`. * Prefer obtaining an entry in one pass from `YamlMap`. * Add tests
2127595 to
db86a0c
Compare
|
@jonasfj I saw #2285 and will definitely do that for the next few PR(s). Changes in this PR for Note
Hope to use this as the baseline once merged. |
Issue(s)
Changes
YamlEditor.removeon a block map/list now removes the entire node completely and leaves no dangling comments or line breaks._removeFromBlockMapand_removeFromBlockListhave been refactored to have shared logic. The heuristics for performing their edits are quite similar.Disclaimers
This is a positive but breaking change. I have not changed the failing tests to showcase difference in output once/if this change lands.
Rationale
While
YamlEditoritself doesn't support insertingScalarStyle.FOLDEDandScalarStyle.LITERALstrings with trailing line breaks, there is a probability (even if it's low) that it might get a yaml string with these styles. It would be nice if it can handle this.It uses a "if-not-first-then-discard-all" approach. It scans around the node and checks the next node (if present) for context before performing the edit. Looking ahead is easier than backtracking. See examples.
Case 1: Top level list
Case 2: Top level maps
Case 3: Compact lists
Same logic applies to block maps.
Contribution guidelines:
dart format.Many Dart repos have a weekly cadence for reviewing PRs - please allow for some latency before initial review feedback.
Note: The Dart team is trialing Gemini Code Assist. Don't take its comments as final Dart team feedback. Use the suggestions if they're helpful; otherwise, wait for a human reviewer.