Split out of #31, where this sat as one line of backlog: "In-place edit API preserving comments. glaucus-cst is a genuinely stronger foundation than a round-trip document type, but there is no ergonomic edit API surfaced on top of it yet."
The foundation is not the gap. glaucus-cst already tokenises comments — SyntaxKind::Comment, is_trivia(), children_with_tokens(), text_range() — and Document::set preserves them by construction, because it splices bytes into the source and re-parses rather than mutating a tree. What is missing is the surface to read them.
Scope
impl Document {
/// Comments attached to the value at `path`.
pub fn comments_at(&self, path: &str) -> Comments;
}
pub struct Comments {
pub leading: Vec<&str>, // own-line comments above the value
pub trailing: Option<&str>, // same-line comment after the value
pub inner: Vec<&str>, // comments between collection items
}
Path syntax is Document::get's, unchanged.
Taxonomy
The three-way leading / trailing / inner split is taken from rust-yaml (src/value.rs::Comments), same author and same MIT OR Apache-2.0 licence.
inner is the category that is easy to miss and expensive to add later: comments between sequence items or mapping entries belong to neither the preceding nor the following value, and a two-way leading/trailing split has nowhere to put them. Anything that drops them silently loses data on round-trip.
Do not port the composer
rust-yaml implements this with CommentPreservingComposer producing CommentedValue { value, comments, style } — a parallel value type carrying comments alongside the data, round-tripped by reconstruction.
That is the weaker of the two designs, and #31 already recorded why. Reconstruction has to re-derive formatting it did not capture; the CST does not, because the bytes never left. Porting the composer would replace a stronger foundation with a weaker one.
Take the taxonomy and the test corpus. Leave the implementation.
The flat-tape constraint
glaucus-cst's tree is deliberately flat — every byte-bearing token sorted by start offset under one Root — because parser event spans do not visit byte offsets monotonically, which broke a structural tree (reproduced on test-suite case 26DV).
Attaching a comment to a value is therefore positional, not structural: resolve the path to a byte span via the same resolver get uses, then classify the comment tokens around that span by line relationship. Any design that assumes it can ask a node for its comment children will not work here.
Acceptance
Port these cases from rust-yaml's tests/comment_preservation_tests.rs as the specification — they are where this gets hard:
Plus, specific to the CST design:
Related
Split out of #31, where this sat as one line of backlog: "In-place edit API preserving comments.
glaucus-cstis a genuinely stronger foundation than a round-trip document type, but there is no ergonomic edit API surfaced on top of it yet."The foundation is not the gap.
glaucus-cstalready tokenises comments —SyntaxKind::Comment,is_trivia(),children_with_tokens(),text_range()— andDocument::setpreserves them by construction, because it splices bytes into the source and re-parses rather than mutating a tree. What is missing is the surface to read them.Scope
Path syntax is
Document::get's, unchanged.Taxonomy
The three-way
leading/trailing/innersplit is taken fromrust-yaml(src/value.rs::Comments), same author and sameMIT OR Apache-2.0licence.inneris the category that is easy to miss and expensive to add later: comments between sequence items or mapping entries belong to neither the preceding nor the following value, and a two-way leading/trailing split has nowhere to put them. Anything that drops them silently loses data on round-trip.Do not port the composer
rust-yamlimplements this withCommentPreservingComposerproducingCommentedValue { value, comments, style }— a parallel value type carrying comments alongside the data, round-tripped by reconstruction.That is the weaker of the two designs, and #31 already recorded why. Reconstruction has to re-derive formatting it did not capture; the CST does not, because the bytes never left. Porting the composer would replace a stronger foundation with a weaker one.
Take the taxonomy and the test corpus. Leave the implementation.
The flat-tape constraint
glaucus-cst's tree is deliberately flat — every byte-bearing token sorted by start offset under oneRoot— because parser event spans do not visit byte offsets monotonically, which broke a structural tree (reproduced on test-suite case26DV).Attaching a comment to a value is therefore positional, not structural: resolve the path to a byte span via the same resolver
getuses, then classify the comment tokens around that span by line relationship. Any design that assumes it can ask a node for its comment children will not work here.Acceptance
Port these cases from
rust-yaml'stests/comment_preservation_tests.rsas the specification — they are where this gets hard:inner, not on a neighbour.|or>block; the block's own content must not be mistaken for one.&anchorbelongs to the value, not the anchor property.---markers belongs to the following document, not the preceding one.Plus, specific to the CST design:
Document::parse(src).comments_at(p)thenseton an unrelated path leaves the comments atpbyte-identical.Comments, not an error.Related
Document::set/insert/insert_atalready preserve comments; this issue is the read side of the same API.