PureXML/Sources/Validation/BuiltinValidation.swift
Mihaela Mihaljevic 380160cc2b refactor(validation): decompose XSD instance validation into composable rules
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.
2026-07-12 14:12:17 +02:00

231 lines
9.3 KiB
Swift

public extension PureXML.Validation {
/// The shipped builtin validation rules, keyed by stable description strings.
/// Reference rules through KeyPath at `BuiltinValidation.Type` so they can be
/// added or removed by identity (`withoutValidating`).
enum BuiltinValidation {
// MARK: Structural
public static var uniqueAttributes: Validation<PureXML.Model.Element, Void> {
Structural.uniqueAttributes
}
// MARK: DTD
public static var dtdContentModel: Validation<PureXML.Model.Element, DTDSchema> {
DTD.contentModel
}
public static var dtdRequiredAttributes: Validation<PureXML.Model.Element, DTDSchema> {
DTD.requiredAttributes
}
public static var dtdFixedAttributeValues: Validation<PureXML.Model.Element, DTDSchema> {
DTD.fixedAttributeValues
}
public static var dtdEnumeratedAttributeValues: Validation<PureXML.Model.Element, DTDSchema> {
DTD.enumeratedAttributeValues
}
public static var dtdTokenizedAttributeTypes: Validation<PureXML.Model.Element, DTDSchema> {
DTD.tokenizedAttributeTypes
}
public static var dtdNotationAttributes: Validation<PureXML.Model.Element, DTDSchema> {
DTD.notationAttributes
}
public static var dtdUndeclaredElement: Validation<PureXML.Model.Element, DTDSchema> {
DTD.undeclaredElement
}
public static var dtdUndeclaredAttributes: Validation<PureXML.Model.Element, DTDSchema> {
DTD.undeclaredAttributes
}
public static var dtdDeclarationValidity: Validation<PureXML.Model.Node, DTDSchema> {
DTD.declarationValidity
}
public static var dtdRootElementType: Validation<PureXML.Model.Node, DTDSchema> {
DTD.rootElementType
}
public static var dtdIdentifierIntegrity: Validation<PureXML.Model.Node, DTDSchema> {
DTD.identifierIntegrity
}
public static var dtdStandaloneAttributes: Validation<PureXML.Model.Element, DTDSchema> {
DTD.standaloneAttributes
}
public static var dtdStandaloneElementWhitespace: Validation<PureXML.Model.Element, DTDSchema> {
DTD.standaloneElementWhitespace
}
public static var dtdParseAdvisories: Validation<PureXML.Model.Node, DTDSchema> {
DTD.parseAdvisories
}
// MARK: HTML
public static var htmlVoidElementsAreEmpty: Validation<PureXML.Model.Element, Void> {
HTML.voidElementsAreEmpty
}
public static var htmlRequiredParent: Validation<PureXML.Model.Element, Void> {
HTML.requiredParent
}
public static var htmlUniqueIdentifiers: Validation<PureXML.Model.Node, Void> {
HTML.uniqueIdentifiers
}
// MARK: XSD schema consistency
public static var xsdFinalRespected: Validation<PureXML.Schema.SchemaTypeFact, PureXML.Schema.CompiledSchemaFacts> {
PureXML.Validation.XSDSchema.finalRespected
}
public static var xsdRestrictionsAreSubsets: Validation<PureXML.Schema.SchemaTypeFact, PureXML.Schema.CompiledSchemaFacts> {
PureXML.Validation.XSDSchema.restrictionsAreSubsets
}
// MARK: Conformance
public static var conformanceMatchesExpected: Validation<ConformanceCase, Void> {
Conformance.matchesExpected
}
// MARK: XSD streaming
public static var xsdStreamingShallowValidity: Validation<PureXML.Schema.ResolvedElement, PureXML.Schema.ComplexValidator> {
PureXML.Schema.ComplexValidator.shallowValidity
}
public static var xsdStreamingIdConsistency: Validation<PureXML.Schema.ComplexValidator, Void> {
PureXML.Schema.ComplexValidator.idConsistency
}
/// Stable ids for each shipped builtin rule (matches ``BuiltinValidation`` properties).
public static let allRuleIDs: [String] = [
"uniqueAttributes",
"dtdContentModel",
"dtdRequiredAttributes",
"dtdFixedAttributeValues",
"dtdEnumeratedAttributeValues",
"dtdTokenizedAttributeTypes",
"dtdNotationAttributes",
"dtdUndeclaredElement",
"dtdUndeclaredAttributes",
"dtdDeclarationValidity",
"dtdRootElementType",
"dtdIdentifierIntegrity",
"dtdStandaloneAttributes",
"dtdStandaloneElementWhitespace",
"dtdParseAdvisories",
"htmlVoidElementsAreEmpty",
"htmlRequiredParent",
"htmlUniqueIdentifiers",
"xsdNilAttributeRequiresNillable",
"xsdNilElementMustBeEmpty",
"xsdNilElementNoFixedConstraint",
"xsdFixedElementNoChildren",
"xsdFixedElementValueMatches",
"xsdEmptyContentForbidsChildren",
"xsdSimpleContentForbidsChildren",
"xsdSimpleContentTypeValid",
"xsdTextForbidden",
"xsdWildcardElementUndeclared",
"xsdSimpleTypeDisallowedAttribute",
"xsdSimpleTypeForbidsChildren",
"xsdSimpleTypeValueValid",
"xsdTypeReferenceResolves",
"xsdContentModelStructure",
"xsdAttributeTypeValid",
"xsdAttributeFixedMatches",
"xsdAttributeRequiredPresent",
"xsdAttributeSingleID",
"xsdAttributeDeclaredOrPermitted",
"xsdWildcardAttributeUndeclared",
"xsdWildcardAttributeTypeValid",
"xsdWildcardAttributeFixedMatches",
"xsdXsiTypeSubstitutionValid",
"xsdXsiTypeOverrideResolves",
"xsdIdIdrefConsistent",
"xsdIdentityConstraintXPathsValid",
"xsdIdentityKeyFieldPresent",
"xsdIdentityValueUnique",
"xsdIdentityKeyrefResolves",
"xsdIdentityFieldCardinality",
"xsdIdentityFieldMustBeSimple",
"xsdFinalRespected",
"xsdRestrictionsAreSubsets",
"conformanceMatchesExpected",
"xsdStreamingShallowValidity",
"xsdStreamingIdConsistency",
]
/// Every builtin rule description, in deterministic order, for configuration-pin tests.
public static var allDescriptions: [String] {
[
uniqueAttributes.description,
dtdContentModel.description,
dtdRequiredAttributes.description,
dtdFixedAttributeValues.description,
dtdEnumeratedAttributeValues.description,
dtdTokenizedAttributeTypes.description,
dtdNotationAttributes.description,
dtdUndeclaredElement.description,
dtdUndeclaredAttributes.description,
dtdDeclarationValidity.description,
dtdRootElementType.description,
dtdIdentifierIntegrity.description,
dtdStandaloneAttributes.description,
dtdStandaloneElementWhitespace.description,
dtdParseAdvisories.description,
htmlVoidElementsAreEmpty.description,
htmlRequiredParent.description,
htmlUniqueIdentifiers.description,
xsdNilAttributeRequiresNillable.description,
xsdNilElementMustBeEmpty.description,
xsdNilElementNoFixedConstraint.description,
xsdFixedElementNoChildren.description,
xsdFixedElementValueMatches.description,
xsdEmptyContentForbidsChildren.description,
xsdSimpleContentForbidsChildren.description,
xsdSimpleContentTypeValid.description,
xsdTextForbidden.description,
xsdWildcardElementUndeclared.description,
xsdSimpleTypeDisallowedAttribute.description,
xsdSimpleTypeForbidsChildren.description,
xsdSimpleTypeValueValid.description,
xsdTypeReferenceResolves.description,
xsdContentModelStructure.description,
xsdAttributeTypeValid.description,
xsdAttributeFixedMatches.description,
xsdAttributeRequiredPresent.description,
xsdAttributeSingleID.description,
xsdAttributeDeclaredOrPermitted.description,
xsdWildcardAttributeUndeclared.description,
xsdWildcardAttributeTypeValid.description,
xsdWildcardAttributeFixedMatches.description,
xsdXsiTypeSubstitutionValid.description,
xsdXsiTypeOverrideResolves.description,
xsdIdIdrefConsistent.description,
xsdIdentityConstraintXPathsValid.description,
xsdIdentityKeyFieldPresent.description,
xsdIdentityValueUnique.description,
xsdIdentityKeyrefResolves.description,
xsdIdentityFieldCardinality.description,
xsdIdentityFieldMustBeSimple.description,
xsdFinalRespected.description,
xsdRestrictionsAreSubsets.description,
conformanceMatchesExpected.description,
xsdStreamingShallowValidity.description,
xsdStreamingIdConsistency.description,
]
}
}
}