Skip to content

Add YamlReader.CurrentKey for converter context during deserialization#136

Closed
fdcastel wants to merge 1 commit into
xoofx:mainfrom
fdcastel:feature/reader-current-key-context
Closed

Add YamlReader.CurrentKey for converter context during deserialization#136
fdcastel wants to merge 1 commit into
xoofx:mainfrom
fdcastel:feature/reader-current-key-context

Conversation

@fdcastel
Copy link
Copy Markdown
Contributor

Motivation

Custom YamlConverter<T> implementations sometimes need to know which mapping key their value is being deserialized under. For example:

  • Replacing ${KEY} placeholders with the actual dictionary key name
  • Performing key-dependent validation or transformation
  • Logging which property/key triggered an error

Currently, converters have no way to access this context.

Example

monitors:
  google: !http
    name: ${KEY}  # should resolve to "google"
    url: https://google.com
  router: !dns
    name: ${KEY}  # should resolve to "router"
    host: 192.168.1.1

Solution

Add a string? CurrentKey property to YamlReader that tracks the most recent mapping key:

  1. YamlReader.CurrentKey — Public read/write property. Returns null at the top level.
  2. Dictionary converters — Set CurrentKey before reading each value, restore previous key afterward (proper nesting).
  3. Object converters — Set CurrentKey before reading each property value across all 6 key-reading sites.

Key design decisions

  • Save/restore pattern: Each loop saves the previous CurrentKey and restores it after reading, ensuring nested structures see the correct innermost key.
  • Public setter: Allows source-generated converters and advanced user code to participate in key tracking.
  • No performance overhead: Just a single string assignment per mapping entry.

Tests

7 tests covering:

  • Dictionary value converter receives CurrentKey
  • Object property converter receives CurrentKey
  • Nested dictionary properly restores CurrentKey
  • Top-level scalar has null CurrentKey
  • Nested object property sets CurrentKey correctly
  • CurrentKey restoration after nested mapping reads

Expose the most recent mapping key via YamlReader.CurrentKey so that custom
YamlConverter implementations can perform context-dependent transformations.

Built-in dictionary and object converters now set CurrentKey immediately
before reading each value and restore the previous key afterward, ensuring
proper nesting behavior for nested structures.

This enables scenarios like:
- Replacing placeholders (\) with the actual dictionary key
- Context-aware validation based on the property name
- Key-dependent deserialization logic in custom converters
@fdcastel fdcastel marked this pull request as draft March 29, 2026 13:49
@fdcastel
Copy link
Copy Markdown
Contributor Author

Another idea that initially seemed good, but now I’m starting to reconsider. Thoughts?

@xoofx
Copy link
Copy Markdown
Owner

xoofx commented Mar 29, 2026

I have a couple of remarks:

  • Example does not match what it claims to support: name: ${KEY} would only give access to name not the outer google/router properties
  • The use case is limited to reader, but it would need to be extended to writer as well
  • Don't know how/if it could, but as any features in SharpYaml, it would need to also support source generator case

So, it's probably not the right approach.

I would think a more generalized approach of having a "stack" of path items accessible from reader/writer. A "path item" would be a lightweight struct with a kind and an object value or integer value. For example:

  • root: the root object
  • key: a property of the current object with a name as a value
  • value: the value of a property or an element of an array
  • index: an element of an array with an index as a value

Problem with this approach is that it could add quite some overhead. It would need to be benchmarked before/after to see if it's acceptable.

@xoofx xoofx closed this Mar 29, 2026
@fdcastel
Copy link
Copy Markdown
Contributor Author

Thanks! Fully agreed.

I’ll disregard this one and explore a post-processing solution instead; it should be cleaner and involve fewer moving parts.

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.

2 participants