Slice 2 of #94. One call for an editor: PureXML.lint reads the document once into
the ranged, best-effort tree (never throwing), then merges the parse diagnostics
and the validation findings into a single source-ranged, severity-tagged list in
document order.
- LintDiagnostic carries message, severity, and the SourceRange to highlight.
- lint(_:validate:) takes a node-based validate closure that runs over the
RECOVERED tree, so validation works even when the document is not well-formed:
a truncated, schema-invalid document yields both a parse diagnostic and the
validation finding, each with a range.
- Schema.Document gains validate(_ node:) so a caller validates the same tree it
is editing; validate(_ xml:) delegates to it.
Tests cover a clean lint, well-formedness-only lint, a range-located validation
finding, and the both-truncated-and-invalid editor case.