PureXML/Sources/Schema/SchemaCompositionValidations.swift
Mihaela Mihaljevic 97c07e91f4 feat(schema): locate composition/redefine-pass schema diagnostics
Convert the five composition/redefine compile checkers to located findings,
the last of the #169 burndown (#210-#217): a resolved schemaLocation whose
content is not a schema underlines the include/import/redefine reference, a
redefined type that does not restrict or extend itself underlines the
redefined type, a redefined group or attribute group with a malformed
self-reference underlines the offending reference or redefinition, and a
redefined attribute group or model group that does not restrict its original
underlines the redefinition.

To locate the referenced-schema rule, failedSchemaReferences carries the
referencing node, captured at the load-failure site in XSDContext. Only a
top-level reference's node belongs to the main schema tree the diagnostic
resolves against; a failure nested in a loaded sub-document is captured from
a throwaway parse, so it stays unlocated (the prior schema-root behavior)
rather than mis-resolve, a strict improvement.

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). The redefine
checkers had exactly one caller each, so each is renamed in place and the
.unlocated wrap dropped. Adds a located-diagnostics test per node-locatable
checker; the attribute-group and model-group restriction redefine checkers
share the same redefinition-node idiom and are exercised by the XSTS suite.
2026-06-21 19:41:31 +02:00

71 lines
4.1 KiB
Swift

extension PureXML.Validation.SchemaCompile {
/// src-resolve: a resolved `include`/`import`/`redefine` `schemaLocation` (one the
/// loader returned content for) must be a well-formed schema document. The
/// failures are recorded on the context during composition; an unresolved
/// location (the loader returned nothing) is not recorded, since resolution is
/// the processor's choice.
static var referencedSchemasResolveToSchemas: PureXML.Validation.Validation<PureXML.Schema.SchemaCompileRoot, PureXML.Schema.SchemaCompileContext> {
compileRule("A resolved schemaLocation reference is a valid schema") { document in
document.context.failedSchemaReferences.map {
PureXML.Schema.SchemaLocatedFinding(
reason: "the referenced schema document '\($0.location)' is not a valid schema",
node: $0.node,
)
}
}
}
/// src-redefine.5: every type inside `xs:redefine` must restrict or extend the
/// type it redefines (same local name, in the redefining schema's own target
/// namespace).
static var redefinitionsDeriveFromThemselves: PureXML.Validation.Validation<PureXML.Schema.SchemaCompileRoot, PureXML.Schema.SchemaCompileContext> {
compileRule("A redefined type restricts or extends itself") { document in
PureXML.Schema.XSDParser.redefineDerivationFindings(document.containers)
}
}
/// src-redefine.6.1/7.2.1: a redefined group or attribute group has at most one
/// self-reference, and a group self-reference occurs exactly once.
static var redefineSelfReferencesAreWellFormed: PureXML.Validation.Validation<PureXML.Schema.SchemaCompileRoot, PureXML.Schema.SchemaCompileContext> {
compileRule("A redefined group or attribute group has a well-formed self-reference") { document in
PureXML.Schema.XSDParser.redefineSelfReferenceFindings(document.containers)
}
}
/// src-redefine: a redefinition of an attribute group restricts the original, so
/// it may not eliminate a required attribute use the original declares.
static var redefinedAttributeGroupsKeepRequired: PureXML.Validation.Validation<PureXML.Schema.SchemaCompileRoot, PureXML.Schema.SchemaCompileContext> {
compileRule("A redefined attribute group keeps the original's required attributes") { document in
PureXML.Schema.XSDParser.redefineAttributeGroupRestrictionFindings(document.containers)
}
}
/// cos-group-restrict: a model group redefined through `xs:redefine` restricts the
/// original, so its content model must accept a subset of the original's. Reuses
/// the particle-restriction oracle; runs after named types resolve so element type
/// compatibility is available.
static var redefinedGroupsRestrictBase: PureXML.Validation.Validation<PureXML.Schema.SchemaCompileRoot, PureXML.Schema.SchemaCompileContext> {
compileRule("A redefined model group restricts the group it redefines") { document in
guard let namedTypes = document.namedTypes, let derivation = document.derivation else { return [] }
return PureXML.Schema.XSDParser.redefineGroupRestrictionFindings(
document.containers,
context: document.context,
types: namedTypes,
derivation: derivation.typeDerivation,
)
}
}
/// Facet definition validity and pattern syntax validity (XSD Part 2 4.3): a
/// constraining facet must be applicable to and valid for its base type, and a
/// `pattern` must compile. These are gathered during simple-type compilation
/// (where the resolved base type is available) into the context's finding sink,
/// then surfaced here as a named, located validation rather than reported
/// straight to the diagnostics collector during parsing.
static var simpleTypeFacetsAreValid: PureXML.Validation.Validation<PureXML.Schema.SchemaCompileRoot, PureXML.Schema.SchemaCompileContext> {
compileRule("Simple-type facets are valid for their base type") { document in
document.context.facetFindingSink.findings
}
}
}