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.
54 lines
2.7 KiB
Swift
54 lines
2.7 KiB
Swift
/// The overlap tests for a compositional-determinism decision set: a UPA violation
|
|
/// is two DISTINCT particles in one decision set that can match the same element
|
|
/// (same element name, or a wildcard admitting the other's name/namespace). Pure
|
|
/// functions over ``CompItem`` sets, factored out of ``CompWalk`` so the walk file
|
|
/// stays within its length budget; the walk accumulates decision sets and hands
|
|
/// each to ``overlap(_:)``.
|
|
enum CompConflict {
|
|
static func overlap(_ set: [CompItem]) -> String? {
|
|
var nameOwner: [PureXML.Model.QualifiedName: ObjectIdentifier] = [:]
|
|
var wildcards: [(card: PureXML.Schema.Wildcard, particle: ObjectIdentifier)] = []
|
|
for item in set {
|
|
switch item.label {
|
|
case let .name(qname):
|
|
if let owner = nameOwner[qname], owner != item.particle {
|
|
return qname.localName
|
|
}
|
|
if nameOwner[qname] == nil {
|
|
nameOwner[qname] = item.particle
|
|
}
|
|
case let .wildcard(card):
|
|
wildcards.append((card, item.particle))
|
|
}
|
|
}
|
|
for (index, wildcard) in wildcards.enumerated() {
|
|
// A wildcard conflicts with any name it admits, from a distinct particle,
|
|
// and with any other wildcard it intersects, from a distinct particle.
|
|
if nameOwner.contains(where: { wildcard.card.admits($0.key) && $0.value != wildcard.particle }) {
|
|
return "any"
|
|
}
|
|
for other in wildcards[(index + 1)...] where other.particle != wildcard.particle && wildcardsOverlap(wildcard.card, other.card) {
|
|
return "any"
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
static func wildcardsOverlap(_ lhs: PureXML.Schema.Wildcard, _ rhs: PureXML.Schema.Wildcard) -> Bool {
|
|
// Two wildcards overlap when some namespace name is admitted by both. Any
|
|
// two `not` forms always share infinitely many named namespaces; a `not`
|
|
// form overlaps a set when the set holds a named namespace it admits.
|
|
switch (lhs.namespace, rhs.namespace) {
|
|
case (.any, _), (_, .any): true
|
|
case let (.enumerated(lhsSet), .enumerated(rhsSet)): !lhsSet.isDisjoint(with: rhsSet)
|
|
case let (.enumerated(set), .notNamespace(name)), let (.notNamespace(name), .enumerated(set)):
|
|
set.contains { !$0.isEmpty && $0 != name }
|
|
case let (.enumerated(set), .notAbsent), let (.notAbsent, .enumerated(set)):
|
|
set.contains { !$0.isEmpty }
|
|
case (.notNamespace, .notNamespace), (.notNamespace, .notAbsent),
|
|
(.notAbsent, .notNamespace), (.notAbsent, .notAbsent):
|
|
true
|
|
}
|
|
}
|
|
}
|