Tagged.Scalar/Sequence/Mapping gain anchor and style fields (Tagged.ScalarStyle, Tagged.CollectionStyle), Tagged.Node gains an alias(anchor:node:) case carrying both the reference and its resolution, and parseTagged populates all of it from the parse events instead of discarding anchors and expanding aliases into copies. PureYAML.dump(_ node: Tagged.Node, options:) re-emits anchors, alias references, tags, and per-node styles over the document-wide policy. Plain scalars re-emit their source spelling (NO stays NO, an empty null stays empty); literal blocks cover keep chomping, single-line strip chomping, leading blank lines, and whitespace-led first lines via an explicit indentation indicator; folded scalars re-emit as > when the folding rules invert exactly and degrade to a literal block otherwise. The round-trip law parseTagged(dump(parseTagged(d))) == parseTagged(d) is corpus-tested over every real-world fixture, with one documented degradation: single-quoted content containing line breaks re-emits double-quoted, value unchanged. Closes #9
69 lines
2.2 KiB
Swift
69 lines
2.2 KiB
Swift
public extension PureYAML.Tagged {
|
|
/// YAML node tree that preserves explicit source tags, anchors, aliases,
|
|
/// and per-node presentation styles.
|
|
///
|
|
/// An `alias` case carries both the `*name` anchor it referenced and the
|
|
/// node it resolved to, so value-oriented consumers can read through the
|
|
/// alias without a separate resolution step while emitters can re-emit
|
|
/// the reference instead of expanding it. Resolution cannot cycle: the
|
|
/// composer registers an anchor only after its node is fully composed, so
|
|
/// a self-referential alias is an `undefinedAlias` parse error.
|
|
indirect enum Node: Equatable, Sendable {
|
|
case scalar(Scalar)
|
|
case sequence(Sequence)
|
|
case mapping(Mapping)
|
|
case alias(anchor: String, node: Node)
|
|
|
|
public var tag: Tag? {
|
|
switch self {
|
|
case let .mapping(mapping):
|
|
mapping.tag
|
|
case let .scalar(scalar):
|
|
scalar.tag
|
|
case let .sequence(sequence):
|
|
sequence.tag
|
|
case .alias:
|
|
nil
|
|
}
|
|
}
|
|
|
|
public var kind: NodeKind {
|
|
switch self {
|
|
case .mapping:
|
|
.mapping
|
|
case .scalar:
|
|
.scalar
|
|
case .sequence:
|
|
.sequence
|
|
case .alias:
|
|
.alias
|
|
}
|
|
}
|
|
|
|
/// The `&name` anchor attached to this node, `nil` when unanchored.
|
|
/// An alias reports the anchor it references.
|
|
public var anchor: String? {
|
|
switch self {
|
|
case let .mapping(mapping):
|
|
mapping.anchor
|
|
case let .scalar(scalar):
|
|
scalar.anchor
|
|
case let .sequence(sequence):
|
|
sequence.anchor
|
|
case let .alias(anchor, _):
|
|
anchor
|
|
}
|
|
}
|
|
|
|
/// The node an alias resolved to; any other node returns itself.
|
|
public var resolved: Node {
|
|
switch self {
|
|
case .mapping, .scalar, .sequence:
|
|
self
|
|
case let .alias(_, node):
|
|
node
|
|
}
|
|
}
|
|
}
|
|
}
|