Skip to main content

blitz_dom_api/
error.rs

1//! The error type every operation returns.
2
3use blitz_dom::NodeId;
4
5use crate::atom::AtomId;
6
7/// Why a DOM operation could not be performed.
8///
9/// Deliberately narrow. Most of `blitz-script`'s operations are *tolerant*
10/// where the DOM specification is strict: reading an attribute off a node that
11/// is not an element yields "absent" rather than throwing, and removing a
12/// child that is not a child removes it from wherever it actually is. Those
13/// behaviours are copied rather than corrected, so they do not appear here.
14/// What does appear is every case where `blitz-script` itself raises, plus the
15/// tree invariants it asserts with `expect`.
16#[derive(Debug, Clone, PartialEq, Eq)]
17pub enum DomError {
18    /// The node id does not name a node in this document.
19    ///
20    /// Only produced where `blitz-script` would panic rather than return.
21    NodeNotFound(NodeId),
22    /// The document has no root element, so there is nothing to answer with.
23    NoRootElement,
24    /// A selector string could not be parsed.
25    ///
26    /// `blitz-script` swallows this: `querySelector` returns `null`, `matches`
27    /// returns `false`, `closest` searches an empty match set. This crate
28    /// surfaces it instead, and the reparenting diff for each of those call
29    /// sites is a trailing `.ok().flatten()` or `.unwrap_or_default()`.
30    InvalidSelector(String),
31    /// A `classList` token was empty or contained ASCII whitespace.
32    ///
33    /// `blitz-script` raises a `SyntaxError` here; this is the same case.
34    InvalidClassToken(String),
35    /// An [`AtomId`] was resolved against an interner that did not mint it.
36    UnknownAtom(AtomId),
37    /// A structural invariant the operation relies on did not hold.
38    ///
39    /// `compare_document_position` is the only current source: it walks to a
40    /// common ancestor and then indexes into it, and `blitz-script` asserts
41    /// both steps with `expect`. A facade must not take the process down over
42    /// a malformed tree, so the assertion becomes this.
43    TreeInvariant(&'static str),
44}
45
46impl std::fmt::Display for DomError {
47    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
48        match self {
49            Self::NodeNotFound(id) => write!(f, "no node with id {id:?} in this document"),
50            Self::NoRootElement => write!(f, "document has no root element"),
51            Self::InvalidSelector(selector) => write!(f, "could not parse selector `{selector}`"),
52            Self::InvalidClassToken(token) => write!(
53                f,
54                "classList token `{token}` must be non-empty and contain no ASCII whitespace"
55            ),
56            Self::UnknownAtom(atom) => write!(f, "{atom:?} was not produced by this interner"),
57            Self::TreeInvariant(what) => write!(f, "document tree invariant violated: {what}"),
58        }
59    }
60}
61
62impl std::error::Error for DomError {}