PureYAML/Sources/Parsing/EventComposer.Merge.swift
Mihaela M 9ae6c3baff refactor(parsing): share merge-key resolution between composers
The buffered and streaming event composers each carried an identical
copy of the merge-key (<<) override logic and its invalid-value error.
Extract both into one internal Parsing.MergeResolution helper so the
precedence rules (local keys win, earlier sources win, inherited then
local order) have a single source of truth. No behavior change; all
tests pass.
2026-06-26 05:50:28 +02:00

78 lines
2.6 KiB
Swift

extension PureYAML.Parsing.EventComposer {
struct ComposedMappingKey {
var keyNode: PureYAML.Model.Key
var scalarValue: String?
var tag: String?
var style: PureYAML.Parsing.ScalarStyle?
var isMergeKey: Bool {
guard let scalarValue else {
return false
}
return tag == "tag:yaml.org,2002:merge"
|| (tag == nil && style == .plain && scalarValue == "<<")
}
}
mutating func composeMergeSources() throws -> [[PureYAML.Model.Pair]] {
guard let event = current else {
throw unexpectedEvent(expected: "merge value")
}
switch event {
case .sequenceStart:
return try composeMergeSequenceSources()
default:
let value = try composeNode()
return try mergeSources(from: value, mark: event.mark)
}
}
mutating func composeMergeSequenceSources() throws -> [[PureYAML.Model.Pair]] {
_ = try expect("merge sequence start") { event in
if case .sequenceStart = event {
return true
}
return false
}
var sources: [[PureYAML.Model.Pair]] = []
while current?.isSequenceEnd != true {
guard let event = current else {
throw unexpectedEvent(expected: "merge sequence item")
}
let value = try composeNode()
try sources.append(mergeSequenceItemSource(from: value, mark: event.mark))
}
_ = try expect("merge sequence end") { $0.isSequenceEnd }
return sources
}
func mergeSources(
from value: PureYAML.Model.Value,
mark: PureYAML.Parsing.Mark,
) throws -> [[PureYAML.Model.Pair]] {
switch value {
case let .mapping(mapping):
return [mapping.pairs]
case let .sequence(values):
return try values.map { value in
guard case let .mapping(mapping) = value else {
throw PureYAML.Parsing.MergeResolution.invalidMergeValue(mark: mark)
}
return mapping.pairs
}
case .bool, .double, .int, .null, .string:
throw PureYAML.Parsing.MergeResolution.invalidMergeValue(mark: mark)
}
}
func mergeSequenceItemSource(
from value: PureYAML.Model.Value,
mark: PureYAML.Parsing.Mark,
) throws -> [PureYAML.Model.Pair] {
guard case let .mapping(mapping) = value else {
throw PureYAML.Parsing.MergeResolution.invalidMergeValue(mark: mark)
}
return mapping.pairs
}
}