The two monolithic XSD content/identity rules only satisfied the OpenAPIKit validation idiom at the wrong granularity: no per-constraint removability, no isolable failing/near-miss tests. Split them into 32 named rules, each finding tagged at its origin and cached per XSDContext so the walk still runs once per document (the #101 decision against duplicating XSD's recursive type resolution still holds). Wired the streaming path's ID/IDREF and identity checks through the same framework instead of calling the validators imperatively, and added the unwrapAndLookup combinator the rule already named as required. Also includes the mandated repo-wide swiftformat/swiftlint pass.
47 lines
2.5 KiB
Swift
47 lines
2.5 KiB
Swift
extension PureXML.Schema.IdentityValidator {
|
|
/// Whether the field's DECLARED target is a complex type with non-simple content
|
|
/// (empty or element-only/mixed), which is not a valid identity field even when its
|
|
/// instance node has no element children (an attributes-only element, XSTS idG006).
|
|
/// Resolved through the schema type model: the selector target's type is looked up,
|
|
/// the field's same-named child element found in its content model, and its declared
|
|
/// type classified. A simple/simpleContent type, a type reached only through a
|
|
/// reference, a complex field path, or an unresolvable target is left alone, so no
|
|
/// valid field is rejected (cvc-identity-constraint.3 / c-fields-xpaths).
|
|
func fieldTargetIsComplexNonSimple(_ field: String, at target: PureXML.Model.TreeNode) -> Bool {
|
|
guard !field.contains(where: { "@/[(.".contains($0) }), let targetName = target.name,
|
|
case let .complex(targetComplex)? = declaredType(of: targetName),
|
|
let fieldType = childElementType(named: field, in: targetComplex.content),
|
|
case let .complex(fieldComplex) = fieldType
|
|
else { return false }
|
|
if case .simpleContent = fieldComplex.content {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
/// The declared `ElementType` of a global element, by namespaced or local key.
|
|
private func declaredType(of name: PureXML.Model.QualifiedName) -> PureXML.Schema.ElementType? {
|
|
types[PureXML.Schema.XSDParser.elementDeclarationKey(name)] ?? types[PureXML.Schema.XSDParser.elementKey(name.localName)]
|
|
}
|
|
|
|
/// The declared type of the first element named `local` directly within a content
|
|
/// model (descending through model groups), or nil when none matches.
|
|
private func childElementType(named local: String, in content: PureXML.Schema.ContentType) -> PureXML.Schema.ElementType? {
|
|
switch content {
|
|
case let .elementOnly(particle), let .mixed(particle): childElementType(named: local, in: particle)
|
|
default: nil
|
|
}
|
|
}
|
|
|
|
private func childElementType(named local: String, in particle: PureXML.Schema.Particle) -> PureXML.Schema.ElementType? {
|
|
switch particle.term {
|
|
case let .element(name, type, _, _, _, _):
|
|
name.localName == local ? type : nil
|
|
case let .group(group):
|
|
group.particles.lazy.compactMap { childElementType(named: local, in: $0) }.first
|
|
case .wildcard:
|
|
nil
|
|
}
|
|
}
|
|
}
|