The validation module already implemented the composable-rule idiom under its own names (Check/Issue/SubjectContext) and a value-type Validator with duplicated traversal machinery per layer. Renamed the core types to the canonical names (Validation/ValidationError/ValidationErrorCollection/ ValidationContext/BuiltinValidation/AnyValidation), converted Validator to a reference-type class with the two-tier default-rule split, and genericized it over both Subject and Document via a new Traversable protocol so the model and tagged layers share one walk engine instead of two copies. Wired the JSON-representability rule set into the same shape and closed the two missing pieces (unwrap combinator, JSON coverage/config-pin tests).
36 lines
1.5 KiB
Swift
36 lines
1.5 KiB
Swift
public extension PureYAML.Validation {
|
|
/// The caseless namespace of built-in type-directed checks, referenceable by name.
|
|
enum BuiltinValidation {
|
|
/// Reports each duplicate key within a single mapping. The type-directed counterpart of the
|
|
/// legacy `Rule.mappingKeysAreUnique`; fires on `Model.Mapping` values directly rather than
|
|
/// switching on a `Model.Value`.
|
|
public static var mappingKeysAreUnique: Validation<PureYAML.Model.Mapping, PureYAML.Model.Value> {
|
|
Validation(description: "Mapping keys are unique") { context in
|
|
var seen = Set<PureYAML.Model.Key>()
|
|
var errors: [ValidationError] = []
|
|
for pair in context.subject.pairs where !seen.insert(pair.keyNode).inserted {
|
|
errors.append(ValidationError(
|
|
severity: .error,
|
|
reason: "Duplicate mapping key '\(pair.keyNode.description)'",
|
|
path: context.path.appending(pair.keyNode.pathComponent),
|
|
))
|
|
}
|
|
return errors
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
extension PureYAML.Model.Key {
|
|
/// The path component a duplicate-key error points at: a plain `.key` for a string key, a
|
|
/// `.complexKey` for a sequence or mapping key (which has no string spelling).
|
|
var pathComponent: PureYAML.Validation.Path.Component {
|
|
switch self {
|
|
case let .string(value):
|
|
.key(value)
|
|
case .mapping, .sequence:
|
|
.complexKey(self)
|
|
}
|
|
}
|
|
}
|