Close the last superficially-located checker (#169): referenceFindings was dispatched as located but its body wrapped the whole aggregate in .unlocated, so every reference-resolution error still collapsed onto the schema root. Convert all six sub-collectors to located findings, each attaching to the node in scope: the core type/base/itemType/memberTypes/ref/ substitutionGroup walk and the xs:-namespace builtin check locate on the referencing element; the simpleContent base-kind check on the restriction; the un-imported-namespace check on the referencing element; the redefine-component-existence check on the redefine's child component; and the import-namespace-agreement check on the import element. Every predicate, aggregation order, and reason string is unchanged; only the location each finding carries differs, verified conformance-neutral by the full XSTS suite (14383 groups, pinned counts unchanged). Removes two dead helpers exposed along the way: the unused referenceErrors [String] wrapper and the unused locatedFindings helper in SchemaCompileValidation. The outer aggregation is rewritten from a single + chain to incremental appends to keep the type-checker within budget. Adds a located-diagnostics test per node-locatable sub-collector; the loader-dependent redefine/import families are exercised by the XSTS suite.
51 lines
3.0 KiB
Swift
51 lines
3.0 KiB
Swift
private typealias ImportNode = PureXML.Schema.XSDNode
|
|
|
|
extension PureXML.Schema.XSDParser {
|
|
/// XSD 1.0 `src-import.3.1`/`3.2`: an `import`'s `namespace` attribute must equal
|
|
/// the `targetNamespace` of the schema it resolves to (both present and equal, or
|
|
/// both absent). Runs only past the cross-document skip guard, so the imported
|
|
/// schema is loaded. Checked only when the `schemaLocation` resolved to a loaded
|
|
/// container (an unresolved import is the processor's choice and not an error),
|
|
/// which is the false-positive boundary. Imports keep their own target namespace
|
|
/// (no chameleon), so the imported document's literal `targetNamespace` is used.
|
|
static func importNamespaceFindings(_ context: PureXML.Schema.XSDContext, _ containers: [XSDTree]) -> [PureXML.Schema.SchemaLocatedFinding] {
|
|
var locationTargetNS: [String: String?] = [:]
|
|
for container in containers where ImportNode.localName(container) == "schema" {
|
|
guard let location = context.containerLocations[ObjectIdentifier(container)] ?? nil else { continue }
|
|
locationTargetNS[location] = ImportNode.attribute(container, "targetNamespace")
|
|
}
|
|
var findings: [PureXML.Schema.SchemaLocatedFinding] = []
|
|
for container in containers {
|
|
for node in descendants(container, named: "import") where node.name?.namespaceURI == xsdNamespace {
|
|
guard let location = ImportNode.attribute(node, "schemaLocation"),
|
|
locationTargetNS.keys.contains(location)
|
|
else { continue }
|
|
let imported = locationTargetNS[location] ?? nil
|
|
let declared = ImportNode.attribute(node, "namespace")
|
|
if declared != imported {
|
|
findings.append(PureXML.Schema.SchemaLocatedFinding(
|
|
reason: "import of '\(location)' declares namespace '\(declared ?? "(none)")', not the imported target namespace '\(imported ?? "(none)")'",
|
|
node: node,
|
|
))
|
|
}
|
|
}
|
|
}
|
|
return findings
|
|
}
|
|
|
|
/// src-redefine.5: a type inside `xs:redefine` must restrict or extend the type it
|
|
/// redefines, which lives in the redefining schema's OWN target namespace. So a
|
|
/// base bound to an EXPLICIT different namespace (for example an imported type
|
|
/// with the same local name) is not self and is invalid. A base with no resolvable
|
|
/// namespace is left alone, which keeps this from ever over-rejecting a
|
|
/// same-local-name self-reference.
|
|
static func redefineBaseIsForeign(_ type: XSDTree, _ rawBase: String?) -> Bool {
|
|
guard let rawBase else { return false }
|
|
let schema = ImportNode.schemaOwner(type)
|
|
let targetNamespace = ImportNode.attribute(schema, "targetNamespace")
|
|
let bindings = ImportNode.namespaceBindings(of: schema)
|
|
guard let baseNamespace = ImportNode.referenceNamespace(rawBase, bindings) else { return false }
|
|
return baseNamespace != targetNamespace
|
|
}
|
|
}
|