updated vendor
This commit is contained in:
+152
@@ -0,0 +1,152 @@
|
||||
// Copyright 2025 The go-yaml Project Contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Desolver stage: Removes inferable tags from YAML nodes.
|
||||
// This is the inverse of the Resolver - it walks a tagged node tree and
|
||||
// removes tags that can be inferred during parsing, producing cleaner YAML
|
||||
// output without unnecessary type annotations.
|
||||
|
||||
package libyaml
|
||||
|
||||
// Desolver handles tag removal for YAML nodes during serialization.
|
||||
// It removes tags that would be automatically resolved to the same type
|
||||
// during parsing, making the output cleaner and more readable.
|
||||
type Desolver struct {
|
||||
opts *Options
|
||||
}
|
||||
|
||||
// NewDesolver creates a new Desolver with the given options.
|
||||
func NewDesolver(opts *Options) *Desolver {
|
||||
return &Desolver{opts: opts}
|
||||
}
|
||||
|
||||
// Desolve walks the node tree and removes tags that can be inferred.
|
||||
// This is the inverse of Resolver - it takes a fully-tagged node tree
|
||||
// (from Representer) and removes unnecessary tags to produce clean output.
|
||||
//
|
||||
// For scalar nodes: if the value would resolve to the same tag when parsed,
|
||||
// the tag is removed. For strings that would resolve differently, the tag is
|
||||
// removed and quoting style is set to preserve the string type.
|
||||
//
|
||||
// For collection nodes (maps/sequences): default tags (!!map, !!seq) are
|
||||
// removed since they're implied by the structure.
|
||||
func (d *Desolver) Desolve(n *Node) {
|
||||
if n == nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch n.Kind {
|
||||
case ScalarNode:
|
||||
d.desolveScalar(n)
|
||||
case DocumentNode, SequenceNode, MappingNode:
|
||||
d.desolveCollection(n)
|
||||
// Recursively desolve children
|
||||
for _, child := range n.Content {
|
||||
d.Desolve(child)
|
||||
}
|
||||
case AliasNode:
|
||||
// Alias nodes don't have tags to remove
|
||||
}
|
||||
}
|
||||
|
||||
// desolveScalar removes tags from scalar nodes when they can be inferred.
|
||||
func (d *Desolver) desolveScalar(n *Node) {
|
||||
// If explicitly tagged by user (TaggedStyle), keep it
|
||||
if n.Style&TaggedStyle != 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// Empty tag means it's already untagged - nothing to do
|
||||
if n.Tag == "" {
|
||||
return
|
||||
}
|
||||
|
||||
stag := shortTag(n.Tag)
|
||||
|
||||
// Check if this is a standard scalar tag that we can potentially remove
|
||||
isStandardTag := false
|
||||
switch stag {
|
||||
case nullTag, boolTag, strTag, intTag, floatTag, timestampTag:
|
||||
isStandardTag = true
|
||||
case binaryTag:
|
||||
// Binary scalars are not implicitly resolvable - never remove.
|
||||
return
|
||||
case mergeTag:
|
||||
// Elide the implicit !!merge tag when the value is the canonical
|
||||
// merge key marker. The TaggedStyle early-return above already
|
||||
// preserves !!merge when it was explicit in the source.
|
||||
if n.Value == "<<" {
|
||||
n.Tag = ""
|
||||
}
|
||||
return
|
||||
default:
|
||||
// Custom tag - preserve it
|
||||
return
|
||||
}
|
||||
|
||||
// Only process standard tags from here
|
||||
if !isStandardTag {
|
||||
return
|
||||
}
|
||||
|
||||
// What tag would this value resolve to?
|
||||
rtag, _ := resolve("", n.Value)
|
||||
|
||||
// If resolved tag matches current tag, we can elide the tag
|
||||
if rtag == stag {
|
||||
// Tag can be inferred - remove it
|
||||
n.Tag = ""
|
||||
} else if stag == strTag {
|
||||
// This is a string type, but would resolve to something else.
|
||||
// Remove the tag and force quoting to preserve string type.
|
||||
n.Tag = ""
|
||||
// If not already quoted, set quote style based on content
|
||||
if n.Style&(SingleQuotedStyle|DoubleQuotedStyle|LiteralStyle|FoldedStyle) == 0 {
|
||||
// Determine quote style based on options or default to single quotes
|
||||
if d.opts != nil {
|
||||
// Convert ScalarStyle to Style
|
||||
switch d.opts.QuotePreference.ScalarStyle() {
|
||||
case DOUBLE_QUOTED_SCALAR_STYLE:
|
||||
n.Style |= DoubleQuotedStyle
|
||||
default:
|
||||
n.Style |= SingleQuotedStyle
|
||||
}
|
||||
} else {
|
||||
n.Style |= SingleQuotedStyle
|
||||
}
|
||||
}
|
||||
} else if stag == floatTag || stag == intTag {
|
||||
// For numeric type mismatches (like float64(1) → "1" with !!float tag):
|
||||
// Elide the tag and let YAML resolve naturally.
|
||||
// Without the tag, "1" resolves as !!int, which may change the type,
|
||||
// but that's acceptable for cleaner output (and matches old behavior).
|
||||
n.Tag = ""
|
||||
}
|
||||
// For other standard tags with mismatches, keep the tag to preserve type
|
||||
}
|
||||
|
||||
// desolveCollection removes default tags from collection nodes.
|
||||
func (d *Desolver) desolveCollection(n *Node) {
|
||||
// If explicitly tagged by user, keep it
|
||||
if n.Style&TaggedStyle != 0 {
|
||||
return
|
||||
}
|
||||
|
||||
stag := shortTag(n.Tag)
|
||||
switch n.Kind {
|
||||
case MappingNode:
|
||||
// !!map is the default for mappings - remove it
|
||||
if stag == mapTag {
|
||||
n.Tag = ""
|
||||
}
|
||||
case SequenceNode:
|
||||
// !!seq is the default for sequences - remove it
|
||||
if stag == seqTag {
|
||||
n.Tag = ""
|
||||
}
|
||||
case DocumentNode:
|
||||
// Documents don't have tags in YAML output
|
||||
n.Tag = ""
|
||||
}
|
||||
// For other tags, keep them - they're explicit type information
|
||||
}
|
||||
Reference in New Issue
Block a user