Skip to content

Update Rust crate noyalib to 0.0.27 - #154

Open
renovate[bot] wants to merge 1 commit into
developfrom
renovate/noyalib-0.x
Open

Update Rust crate noyalib to 0.0.27#154
renovate[bot] wants to merge 1 commit into
developfrom
renovate/noyalib-0.x

Conversation

@renovate

@renovate renovate Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

This PR contains the following updates:

Package Type Update Change
noyalib dependencies patch 0.0.230.0.27

Release Notes

sebastienrousseau/noyalib (noyalib)

v0.0.27

Compare Source

Two correctness fixes in alias and merge-key handling, both found by
consumers pointing a real workload at a published release.

Fixed
  • An alias used as a value beside a merge key came back unresolved
    (#​301, reported and diagnosed by
    @​mathstuf, fixed in #​304).

    base: &b   { x: 1, y: 1 }
    other: &other 2
    overridden:
      <<: *b
      y: *other        # deserialised as the string "other", not 2

    peek_event and next_event each read from either the replay stack or
    the parser, and resolved aliases on the parser branch only — then
    labelled both results processed. An alias arriving through replay was
    therefore stored as though it were fully processed while still being an
    Event::Alias. The replay stack only exists once a merge has injected
    something, which is why the same document works with the alias written
    above the <<: line and fails below it.

    Alias resolution now runs whichever branch the event came from, in one
    process_event; anchor_and_record is the single place doing anchor
    bookkeeping; and the lookahead slot is typed (Lookahead::{Raw, Processed}) so its two consumers stop inferring which kind they hold,
    in opposite directions. Inline alias resolutions 3 -> 1, anchor/record
    pairs 3 -> 1.

  • Only a plain << scalar is a merge key. The YAML merge type gives
    tag:yaml.org,2002:merge to a plain <<; a quoted "<<", and an
    alias resolving to the string <<, both resolve to
    tag:yaml.org,2002:str. Both were being read as merge instructions.

    By the time a key reaches the mapping arms it is a
    Value::String("<<") however it was written, so eligibility is now
    decided at each scalar-resolution site and carried in the frame.
    loader.rs holds two complete loaders, each with its own frame enum
    and its own pair of merge checks — four sites in all. The first attempt
    patched one and changed nothing observable.

    Value::apply_merge remains style-blind by nature and is documented as
    such: it operates on an already-built Value, where presentation does
    not exist.

    Behaviour change. A document where a quoted "<<" or an alias to
    << currently triggers a merge will stop merging and gain a literal
    << key instead. This is spec-correct, but it is silent — no
    error is raised. If you rely on either spelling, quote-strip it to a
    plain << before upgrading.

Added
  • merge_keys_with_aliases example — merge keys and aliases in one
    mapping, and which spellings of << are merges.
  • Benchmarks for <<: expansion (merge_key_single_anchor,
    merge_key_sequence_of_anchors, merge_key_quoted_is_ordinary, and a
    merge_key_absent_baseline). The existing merge_small /
    merge_nested / merge_concat time Value::merge(), an API method on
    an already-parsed value; nothing measured merge-key expansion during
    parsing.
  • 63 tests across three tiers: 13 unit, 35 integration (the merge-key
    matrix asserts every case on both the streaming and AST paths), and
    8 regression, plus a differential oracle comparing from_str::<Value>
    against load_all, which shares no lookahead code.
Changed
  • doc/ECOSYSTEM.md and doc/scorecard.json regenerated against this
    release. The previous scorecard's audit_vulnerabilities rows were
    never actually measured — cargo audit was exiting 101 under a
    shadowing shell alias and the probe's fallback read that as zero
    advisories. That probe was fixed in v0.0.26; this is the first
    scorecard where those rows are earned.

v0.0.26

Compare Source

Fixed
  • remove left a whitespace-only line in a wrapped flow collection
    (#​294, reported and fixed by @​zoosky,
    PR #​296). A flow collection written one member per line —

    ports: [
      80,
      443,
    ]

    — lost the member but kept its indentation, so remove("ports[0]")
    wrote onto a line that had held content. The value round-tripped
    unchanged, so this was never corruption; it was trailing whitespace in
    a patch, which git diff --check, yamllint's trailing-spaces and
    editorconfig-checker all reject. A library whose promise is that an
    edit touches only what the path names should not hand its caller a diff
    their own lint refuses.

    flow_member_range took the member and exactly one separator — right
    for {x: 1, y: 2}, and all a single-line collection ever needs — but
    nothing then asked whether the line had anything left on it. The block
    path had always answered that same question the other way:
    owned_entry_range takes the entry's whole line, indentation included.
    Same operation, same shape, opposite answers.

    The member now takes its whole line when — and only when — it is alone
    on it. The condition is "alone on its line", not "the collection is
    wrapped", so an opening indicator, a sibling member, a trailing comment
    or the closing indicator all keep the line standing and leave those
    outputs byte-identical.

    Unreachable before #​285: a wrapped flow collection did not parse, so
    nothing downstream of the scanner had ever seen one. That is the second
    time in two releases that fixing a parse refusal exposed a defect it
    had been hiding.

    The fix is absorb_emptied_line, named for the existing
    absorb_head_comments it sits beside. Its doc comment draws one
    boundary worth repeating: a comment left on the line keeps the line,
    because what a comment stranded by a removal means is the caller's
    question, not something a whitespace rule should decide.

    42 tests added — 13 from @​zoosky's PR, plus 18 integration and 11 unit
    tests here — and the cst_wrapped_flow_edit example. The unit tests
    were written against an independent implementation of the same fix and
    pass unmodified against this one, which is the closest thing to a
    second opinion a single codebase gets.

  • The ecosystem scorecard scored a security probe it had not run.
    cargo audit --json exits 101 where a user-defined audit = "audit"
    alias in ~/.cargo/config.toml shadows the subcommand and recurses.
    The probe's fallback counted RUSTSEC occurrences in whatever landed on
    stdout, so an error message yielded "0 advisories" and a clean pass —
    the harness's own "no credit for unmeasured work" rule violated in the
    place it matters most. It now invokes cargo-audit directly and treats
    unparsable output as N/A. Exit status alone cannot decide this, because
    cargo-audit also exits non-zero when it genuinely finds advisories;
    the discriminator is whether .vulnerabilities.count parses. The real
    count for this release is 0 across 272 crates, confirmed by running the
    binary directly.

v0.0.25

Compare Source

Four fixes from @​zoosky, all found while
adopting v0.0.24 in yqr, and all cases
where the previous behaviour produced or refused something this codebase
already disagreed with elsewhere.

Each arrived as a reproduction against a published version, a diagnosis
naming the responsible function, a fix, and tests — including the cases
that had to keep failing. Three of the four were found by pointing a real
consumer at a release and reporting what broke, which is the kind of
testing a library cannot do for itself.

Fixed
  • remove wrote an empty collection at its key's own column (#​283,
    PR #​284). A block sequence may sit at its key's column — on: /
    - push is what nearly every GitHub Actions and Ansible file looks
    like. What replaces it may not: {} / [] is a block mapping value,
    and one sharing its key's column does not re-parse as that key's value.

    on:            ->   on:            # before: Ok(()), and unreadable
    - push              []
    jobs: {}            jobs: {}

    The inconsistency was visible from inside: delete the jobs: line and
    the identical removal was refused by the oracle, because the guard
    re-parses with this parser, which accepts on:\n[]\njobs: {} and
    rejects on:\n[]. Same shape, same output spelling — Ok with a
    sibling, refused without one.

    sole_entry_range took the indent from the removed entry's own line,
    which for this layout is the key's column. The constraint is
    "strictly deeper than the key", and the two coincide for every layout
    except this one. The parent key's offset is now threaded down and the
    indent clamped to the key's column + 2 when the entry's own indent does
    not already clear it. A root collection, or one reached through a
    sequence item, has no parent key and is unchanged.

    The head-comment run from #​280 is still absorbed at the entry's own
    column, where those comment lines actually sit — only the replacement
    moves.

  • A wrapped flow collection was refused when its closing indicator sat
    at the parent's column
    (#​285, PR #​286):

    ports: [
      80,
      443,
    ]

    A read refusal, so nothing downstream ran. The indentation check
    exists so that flow content continuing across a line break cannot be
    ambiguous with sibling block content (yaml-test-suite 9C9N) — but that
    rationale is about content. A line whose first character is ] or
    } cannot begin block content, so there is nothing to be ambiguous
    with; the rule was reaching the terminator too.

    The asymmetry was already in the tree: the same closer at column 0 is
    accepted at the root, where self.indent is -1. Only a flow inside a
    block mapping refused it.

    Under-indented flow content stays refused, deliberately — that is
    9C9N's rule and this does not touch it. ports: [ / 80, / ] is
    still an error, as is 9C9N itself, whose third line opens with a scalar
    rather than the indicator.

  • A new key could not be inserted into a mapping whose keys contain a
    ., [ or *, and the refusal blamed a << merge that was not
    there
    (#​288, PR #​289).

    labels:
      app.kubernetes.io/name: web
      app.kubernetes.io/component: frontend

    insert_entry("labels", "tier", "frontend") refused. That is the
    standard Kubernetes label convention, so the shape is everywhere.

    Two sites took the last key from the typed view, composed it back
    into a path string, and re-parsed it — mapping_insert_anchor, and
    insert_entry, which duplicated the logic inline. parse_query_path
    splits on ., [ and * unconditionally, so no such key survives the
    round trip and every entry looked span-less. With no anchor left, the
    only error the function knew about fired: the merge one.

    Two defects nested — a path round trip that no such key survives, and a
    diagnostic asserting a cause rather than reporting an observation.

    The anchor never needed a path. mapping_insert_anchor now walks the
    span tree's entries directly, through a new resolve_tree, and
    insert_entry shares it instead of keeping its own copy. Three things
    fall out, each tested: keys holding [, * or quoted dots insert
    correctly; a mapping whose last entry is an implicit null anchors on
    that entry's key line, so a sibling lands after it rather than
    above it; and a mapping with both a << merge and an entry of its own
    anchors on the entry. A merge-only mapping still refuses, leading
    with what was observed.

    Insert only — set, remove, rename_key and swap_items still
    address through parse_query_path, so a dotted key stays out of reach
    for them. Whether the path grammar should grow an escape form is a
    separate question.

  • An inserted scalar was quoted because some unrelated line was
    quoted
    (#​290). The dominance vote counted only quoted scalars against
    each other — plain ones did not vote — so a single quoted scalar
    anywhere decided the spelling of every later insertion:

    quoted: "30"        # four lines away, untouched by the edit
    labels:
      app: web
      tier: "frontend"  # before — the sibling is plain

    On a Kubernetes manifest the vote was settled by value: "30" in a
    container's env block, arbitrarily far from the labels being edited.
    Nothing was wrong with the value — it round-trips and the document
    stays valid — but the diff a reviewer saw was a quoted value among
    plain ones. It also disagreed with set, which writes plain at the
    same site.

    EmitCtx's doc already stated the intent — an implementation should
    "match the file it is landing in" — so the radius was wrong rather than
    the idea. Insertion now learns from the collection it lands in and only
    falls back to the document-wide vote when that collection has no scalar
    values to learn from.

    Two details decided by implementing it:

    • Only values vote, not keys. Counting scalar tokens across the
      site's byte range cannot tell one from the other, and mapping keys
      are almost always plain — a: "one" / b: "two" would tie two plain
      keys against two quoted values and pick plain, the opposite of what
      the site says. The entry values are read from the span tree instead.
    • Plain needs a strict majority. A tie means the site is genuinely
      mixed (a: 1 beside b: 'two'), and there the quoting already
      present is the better guide. Every case #​290 reports has plain
      winning outright.

    Document::dominant_quote_style is public, documented, and pinned by
    three doctests, so its behaviour is unchanged — this narrows what
    insertion asks, not what that function answers. Of the two options in
    the report this is the second, which leaves the public API alone.

  • remove refuses an alias-valued entry instead of silently doing
    nothing
    (PR #​292). Behaviour change: a call that previously
    returned Ok(()) now returns an error.

    a: &x 1
    b: *x     # remove("b") -> Ok(()), document unchanged

    An alias resolves through to its anchor, so the value span for b
    is the anchor's bytes on another line — before b's own key. The
    range arithmetic degenerated to an empty splice, so the call removed
    nothing and reported success.

    Refusing is what SpanTree::Alias's own documentation already
    prescribes: a write there would splice the anchor's bytes, which
    belong to a different key. The message names the entry and the reason.
    Removing the anchor's own entry still works, as does replace_span
    for callers who want the bytes gone deliberately.

    Present since at least v0.0.24 — reproduced identically on that tag —
    and surfaced by the corrected fuzz invariant below, which asserts that
    an accepted removal changed the source.

Testing
  • The differential fuzz target's remove invariant was unsound (PR
    #​291). fuzz_editors asserted that an accepted remove shrinks the
    parsed value. It does not, under duplicate mapping keys: Value
    deduplicates and the last duplicate wins, so removing one of two 5:
    entries deletes a line from the source while both parses still show
    three keys. A correct edit failed the assertion and fuzz-diff went
    red on main.

    Asserting the source gets shorter is also wrong — removing the only
    entry rewrites "::\n" to "{}\n", which is correct and exactly as
    long. What holds is that the source changed, and that is what the
    target now asserts; the node count is kept only in the non-strict
    direction, which still catches a removal that takes a parent with it.

    remove itself was correct throughout. Both behaviours are pinned in
    tests/cst_remove_fuzz_regressions.rs so they run under the normal
    suite rather than only under a nightly fuzz job.

Changed
  • Per-release notes moved from the repository root to
    doc/release-notes/, renamed to match
    their tags exactly (doc/release-notes/v0.0.17.md documents
    v0.0.17). Moved with git mv, so history follows. Links that
    pointed at the old root paths were updated; deep links to
    RELEASE-NOTES-v0.0.N.md on main will need adjusting.

  • Version → 0.0.25.

v0.0.24

Compare Source

Fixed
  • remove stranded a sole entry's head comment (#​280, reported by
    @​zoosky). The same comment on the same entry was taken when the
    entry had a sibling and left behind when it did not:

    # before, with a sibling            # before, as the last entry
    a:                                  a:
      # documents x                       # documents x
      x: 1                                x: 1
      y: 2                              b: 2
    
    # after: comment removed with x     # after: comment stranded above {}
    a:                                  a:
      y: 2                                # documents x
                                          {}
                                        b: 2

    The two arms derived their range from different things.
    Removal::Line goes through owned_entry_range, which calls
    absorb_head_comments and so owns the contiguous same-indent comment
    run above the entry. Removal::SoleEntry replaced the collection's
    span, and a collection starts at its first entry's content
    below the comment — so the run was never absorbed. Returned Ok, and
    invisible to the typed oracle, because a comment is not in the typed
    value.

    Both paths now share sole_entry_range. Two consequences worth
    naming:

    • The splice can begin above the entry, so the entry's own leading
      whitespace falls inside the replaced range and is written back —
      otherwise a: loses its value entirely rather than gaining {}.
    • Flow collections are excluded. a: {x: 1} starts at the {
      part way along a line whose earlier bytes belong to the key. There
      is no head-comment run to own there, and those bytes are not
      indentation: treating them as such rewrote a: {x: 1} as {}
      and lost the key. Caught by an existing test.

    Unchanged, and now pinned: a comment detached by a blank line, or at a
    different column, is not the entry's and stays put; an inline trailing
    comment sits inside the collection span and was always removed
    correctly.

Changed
  • Dependency updates rolled into this release, superseding #​273, #​274,
    #​275, #​276, #​277 and #​278:
    • jsonschema 0.49.6 → 0.49.9
    • hashbrown 0.15.5 → 0.17.1
    • github/codeql-action/{analyze,init,upload-sarif} 4.37.6 → 4.37.7
    • taiki-e/install-action 2.85.10 → 2.86.1

Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@renovate
renovate Bot force-pushed the renovate/noyalib-0.x branch from 9d962f8 to c0612c6 Compare August 20, 2026 09:57
@renovate renovate Bot changed the title Update Rust crate noyalib to 0.0.24 Update Rust crate noyalib to 0.0.25 Aug 20, 2026
@renovate
renovate Bot force-pushed the renovate/noyalib-0.x branch from c0612c6 to b61e166 Compare August 20, 2026 22:33
@renovate renovate Bot changed the title Update Rust crate noyalib to 0.0.25 Update Rust crate noyalib to 0.0.26 Aug 20, 2026
@renovate
renovate Bot force-pushed the renovate/noyalib-0.x branch from b61e166 to fe06b52 Compare August 21, 2026 17:34
@renovate renovate Bot changed the title Update Rust crate noyalib to 0.0.26 Update Rust crate noyalib to 0.0.27 Aug 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants