SchemaStructure.swift was the last source file at the 400-line cap. The cos-element-consistent check (a complex type's content model may not declare two same-named elements with different types) is a self-contained constraint with its own helpers (collectElementDecls, elementTypeKey) and the contentModelContainers set used only by it. Move that cluster into SchemaElementDeclarationsConsistent.swift; elementDeclsConsistentErrors becomes internal (its sole caller is in SchemaStructure). Pure code move, no behaviour change: SchemaStructure 400 -> 342, new file 59. With this, no source file remains at the 400-line cap. Full suite and the XSTS gate pass unchanged.
60 lines
3.2 KiB
Swift
60 lines
3.2 KiB
Swift
extension PureXML.Schema.XSDParser {
|
|
/// Findings for Element Declarations Consistent (cos-element-consistent): in a
|
|
/// single complex type's content model, two element declarations with the same
|
|
/// name must have the same type. Collects element particles across the content
|
|
/// model (descending through model groups and content-derivation wrappers, not
|
|
/// into a nested type), keyed by name; a name seen with more than one distinct
|
|
/// type definition is a violation. (Substitution-group expansion is not folded
|
|
/// in, an accepted under-rejection.)
|
|
static func elementDeclsConsistentErrors(_ complexType: XSDTree) -> [String] {
|
|
var byName: [String: Set<String>] = [:]
|
|
var inlineCount = 0
|
|
collectElementDecls(complexType, into: &byName, inlineCount: &inlineCount)
|
|
return byName.keys.sorted().compactMap { name in
|
|
(byName[name]?.count ?? 0) > 1
|
|
? "element '\(name)' has inconsistent type definitions in the same content model"
|
|
: nil
|
|
}
|
|
}
|
|
|
|
private static func collectElementDecls(_ node: XSDTree, into byName: inout [String: Set<String>], inlineCount: inout Int) {
|
|
for child in PureXML.Schema.XSDNode.elementChildren(node) where child.name?.namespaceURI == xsdNamespace {
|
|
guard let local = PureXML.Schema.XSDNode.localName(child) else { continue }
|
|
if local == "element" {
|
|
if let name = PureXML.Schema.XSDNode.attribute(child, "name") {
|
|
byName[name, default: []].insert(elementTypeKey(child, inlineCount: &inlineCount))
|
|
}
|
|
// Do not descend into the element's own type definition.
|
|
} else if contentModelContainers.contains(local) {
|
|
collectElementDecls(child, into: &byName, inlineCount: &inlineCount)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// A key identifying an element particle's type definition: its `type`
|
|
/// reference by local name, a distinct token per inline (anonymous) type (two
|
|
/// inline types are never the same definition), or a shared token when the
|
|
/// element is untyped (the ur-type).
|
|
private static func elementTypeKey(_ element: XSDTree, inlineCount: inout Int) -> String {
|
|
if let type = PureXML.Schema.XSDNode.attribute(element, "type") {
|
|
return "type:" + PureXML.Schema.XSDNode.stripPrefix(type.trimmingXMLWhitespace())
|
|
}
|
|
let hasInlineType = PureXML.Schema.XSDNode.elementChildren(element).contains {
|
|
let local = PureXML.Schema.XSDNode.localName($0)
|
|
return local == "complexType" || local == "simpleType"
|
|
}
|
|
if hasInlineType {
|
|
inlineCount += 1
|
|
return "inline:\(inlineCount)"
|
|
}
|
|
return "untyped"
|
|
}
|
|
|
|
/// The model-group and content-derivation elements through which a complex
|
|
/// type's content model extends; the walk descends through these but never
|
|
/// into an element's own type definition (a nested type is a separate model).
|
|
private static let contentModelContainers: Set<String> = [
|
|
"sequence", "choice", "all", "group", "complexContent", "simpleContent", "restriction", "extension",
|
|
]
|
|
}
|