Skip to content

glaucus-cst tokenises comments but exposes no way to read them #48

Description

@elioseverojunior

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:

  • Basic — leading, trailing, and both on one entry.
  • Sequences — comments between items land in inner, not on a neighbour.
  • Multiline strings — a comment after a | or > block; the block's own content must not be mistaken for one.
  • Anchors and aliases — a comment near &anchor belongs to the value, not the anchor property.
  • Quote styles — quoting changes where the value token ends, so trailing detection must follow it.
  • Multi-document — a comment between --- markers belongs to the following document, not the preceding one.
  • Edge cases — comment-only documents, empty input, a comment as the last byte with no trailing newline.
  • Complex — nested mappings and sequences combined.

Plus, specific to the CST design:

  • Round-trip: Document::parse(src).comments_at(p) then set on an unrelated path leaves the comments at p byte-identical.
  • A path that does not resolve returns empty Comments, not an error.
  • Coverage stays at 100%.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestparityCross-implementation parity work

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions