public extension PureXML.Parsing { /// A located problem found while reading a document. Unlike a thrown /// ``ParseError``, a diagnostic does not abort the read: the recovering reader /// records it, repairs as best it can, and continues, so an invalid document /// still yields a best-effort tree alongside the list of what went wrong. struct Diagnostic: Equatable, Sendable, CustomStringConvertible { /// A human-readable, already-located description of the problem. public var message: String /// The source position, when known. public var mark: Mark? public init(message: String, mark: Mark? = nil) { self.message = message self.mark = mark } public var description: String { message } } } extension PureXML.Parsing.Diagnostic { /// Wraps a thrown ``PureXML/Parsing/ParseError`` as a diagnostic, keeping its /// located message and structured position. init(_ error: PureXML.Parsing.ParseError) { self.init(message: error.description, mark: error.mark) } } public extension PureXML.Parsing.ParseError { /// The source position the error occurred at, when the case carries one. var mark: PureXML.Parsing.Mark? { switch self { case .emptyDocument, .malformedEncoding, .notImplemented: nil case let .unexpectedEndOfInput(mark), let .unterminatedTag(mark), let .unterminatedComment(mark), let .unterminatedCDATA(mark), let .expectedName(mark), let .expectedEquals(mark), let .unquotedAttributeValue(mark), let .amplificationLimitExceeded(mark), let .junkAfterDocumentElement(mark), let .unsupportedDoctype(mark), let .malformedDeclaration(mark), let .doubleHyphenInComment(mark), let .rawLessThanInAttribute(mark), let .cdataCloseInContent(mark), let .missingSpaceBeforeAttribute(mark), let .invalidCharacter(mark), let .reservedProcessingInstructionTarget(mark), let .invalidEntityDeclaration(mark), let .invalidAttributeListDeclaration(mark), let .invalidPublicIdentifier(mark): mark case let .unexpectedCharacter(_, mark), let .mismatchedEndTag(_, _, mark), let .namespaceConstraint(_, mark), let .duplicateAttribute(_, mark), let .invalidReference(_, mark), let .undefinedEntity(_, mark), let .recursiveEntity(_, mark), let .unexpectedEndTag(_, mark), let .undefinedNamespacePrefix(_, mark), let .nestingTooDeep(_, mark), let .nameTooLong(_, mark), let .contentTooLong(_, mark), let .invalidContentModel(_, mark): mark } } }