PureXML/Sources/Validation/StructuralValidations.swift
Mihaela Mihaljevic 229d7df3d0 feat(validation,schema): composable validation framework and cross-document composition
Ship the OpenAPIKit-style validation layer (builtin rules, warnings channel,
Validator tiers, coverage gates) and wire XSD compile checks through it. Advance
#161 with chameleon include validation, multi-container reference resolution,
and include targetNamespace composition rules so merged schema sets compile
correctly when a schemaLoader is provided.
2026-06-16 09:57:43 +02:00

53 lines
2.2 KiB
Swift

public extension PureXML.Validation {
/// The schema-independent structural validations: well-formedness rules that
/// hold for any document regardless of a DTD or schema.
enum Structural {
/// An element must not declare the same attribute name twice. Reports one
/// error per duplicate.
public static var uniqueAttributes: Validation<PureXML.Model.Element, Void> {
.init(description: "Element attribute names are unique") { context in
var seen: Set<String> = []
var errors: [ValidationError] = []
for attribute in context.subject.attributes {
let key = attribute.name.description
if !seen.insert(key).inserted {
errors.append(ValidationError(
reason: "Duplicate attribute '\(key)' on <\(context.subject.name.description)>",
at: context.codingPath,
))
}
}
return errors
}
}
/// The default structural rule set.
static var defaults: [Validation<PureXML.Model.Element, Void>] {
[uniqueAttributes]
}
}
}
extension PureXML.Validation.Validator where Document == Void {
/// Validates a node with the structural rules, throwing a
/// ``PureXML/Validation/ValidationErrorCollection`` on any failure.
func validate(_ node: PureXML.Model.Node, strict: Bool = true) throws {
try validate(node, in: (), strict: strict)
}
/// The structural errors for a node, in document order; empty when valid.
func errors(for node: PureXML.Model.Node) -> [PureXML.Validation.ValidationError] {
errors(for: node, in: ())
}
/// The structural warnings for a node, in document order.
func warnings(for node: PureXML.Model.Node) -> [PureXML.Validation.ValidationError] {
warnings(for: node, in: ())
}
/// Every structural finding for a node, errors and warnings together.
func findings(for node: PureXML.Model.Node) -> [PureXML.Validation.ValidationError] {
findings(for: node, in: ())
}
}