public extension PureYAML.Model { /// A value tree annotated with source spans, parallel in shape to ``Value``: every node /// carries its own ``SourceRange`` and its located children. It is produced by the opt-in /// ``PureYAML/parseLocated(_:)`` and ``PureYAML/parseStreamLocated(_:)`` entry points; the /// plain ``Value`` API is unchanged, so source positions never affect value equality, the /// conformance oracle, or any existing consumer. /// /// `value` projects the position-free ``Value`` (identical to what a plain parse returns), /// and `range` is the node's own span, so a consumer can keep operating on ``Value`` and /// consult the located tree only when it needs a location. indirect enum LocatedValue: Equatable, Sendable { /// A leaf scalar (`null`, `bool`, `int`, `double`, or `string`) with its start-anchored span. case scalar(Value, SourceRange) /// A sequence: its located items and the span from its opening to its closing. case sequence([LocatedValue], SourceRange) /// A mapping: its located pairs and the span from its opening to its closing. case mapping([LocatedPair], SourceRange) } } public extension PureYAML.Model.LocatedValue { /// The span of this node. var range: PureYAML.Model.SourceRange { switch self { case let .scalar(_, range), let .sequence(_, range), let .mapping(_, range): range } } /// The position-free value this located node projects to, identical to a plain parse. var value: PureYAML.Model.Value { switch self { case let .scalar(value, _): value case let .sequence(items, _): .sequence(items.map(\.value)) case let .mapping(pairs, _): .mapping(PureYAML.Model.Mapping(pairs.map(\.pair))) } } /// Wrap a plain ``Value`` so every node shares one span. Used where a real per-node span is /// not available (an alias expansion or a merge-inherited pair, whose content is defined /// elsewhere): the whole subtree honestly points at its single reference site. static func synthesized(from value: PureYAML.Model.Value, at range: PureYAML.Model.SourceRange) -> Self { switch value { case .null, .bool, .int, .double, .string: return .scalar(value, range) case let .sequence(items): return .sequence(items.map { synthesized(from: $0, at: range) }, range) case let .mapping(mapping): let pairs = mapping.pairs.map { PureYAML.Model.LocatedPair(keyNode: $0.keyNode, keyRange: range, value: synthesized(from: $0.value, at: range)) } return .mapping(pairs, range) } } }