// NOTE: This file is generated by the templates/template.rb script and should not
// be modified manually. See /home/runner/work/herb/herb/templates/rust/src/errors.rs.erb

use crate::{Location, Position, Token};
use colored::*;

fn escape_string(s: &str) -> String {
  s.replace('\\', "\\\\")
    .replace('\n', "\\n")
    .replace('\r', "\\r")
    .replace('\t', "\\t")
    .replace('"', "\\\"")
}

fn format_string_value(value: &str) -> String {
  format!("\"{}\"", escape_string(value)).green().to_string()
}

fn format_token_value(token: &Option<Token>) -> String {
  token.as_ref().map(|t| t.tree_inspect()).unwrap_or_else(|| "∅".magenta().to_string())
}

fn format_token_type_value(token_type: &Option<String>) -> String {
  token_type.as_ref().map(|t| format!("\"{}\"", t).green().to_string()).unwrap_or_else(|| "∅".magenta().to_string())
}

#[allow(dead_code)]
fn format_position_value(position: &Option<crate::Position>) -> String {
  position.as_ref().map(|p| p.to_string()).unwrap_or_else(|| "∅".magenta().to_string())
}

#[allow(dead_code)]
fn format_size_value(value: usize) -> String {
  value.to_string().magenta().bold().to_string()
}

#[derive(Debug, Clone, PartialEq)]
pub enum ErrorType {
  UnexpectedError,
  UnexpectedTokenError,
  MissingOpeningTagError,
  MissingClosingTagError,
  TagNamesMismatchError,
  VoidElementClosingTagError,
  UnclosedElementError,
  RubyParseError,
  ERBControlFlowScopeError,
  MissingERBEndTagError,
  ERBMultipleBlocksInTagError,
  ERBCaseWithConditionsError,
  ConditionalElementMultipleTagsError,
  ConditionalElementConditionMismatchError,
  InvalidCommentClosingTagError,
  OmittedClosingTagError,
  UnclosedOpenTagError,
  UnclosedCloseTagError,
  UnclosedQuoteError,
  MissingAttributeValueError,
  UnclosedERBTagError,
  StrayERBClosingTagError,
  NestedERBTagError,
  RenderAmbiguousLocalsError,
  RenderMissingLocalsError,
  RenderNoArgumentsError,
  RenderConflictingPartialError,
  RenderInvalidAsOptionError,
  RenderObjectAndCollectionError,
  RenderLayoutWithoutBlockError,
  StrictLocalsPositionalArgumentError,
  StrictLocalsBlockArgumentError,
  StrictLocalsSplatArgumentError,
  StrictLocalsMissingParenthesisError,
  StrictLocalsDuplicateDeclarationError,
  VoidElementContentError,
  DotNotationCasingError,
}

impl ErrorType {
  pub fn as_str(&self) -> &str {
    match self {
      ErrorType::UnexpectedError => "UNEXPECTED_ERROR",
      ErrorType::UnexpectedTokenError => "UNEXPECTED_TOKEN_ERROR",
      ErrorType::MissingOpeningTagError => "MISSING_OPENING_TAG_ERROR",
      ErrorType::MissingClosingTagError => "MISSING_CLOSING_TAG_ERROR",
      ErrorType::TagNamesMismatchError => "TAG_NAMES_MISMATCH_ERROR",
      ErrorType::VoidElementClosingTagError => "VOID_ELEMENT_CLOSING_TAG_ERROR",
      ErrorType::UnclosedElementError => "UNCLOSED_ELEMENT_ERROR",
      ErrorType::RubyParseError => "RUBY_PARSE_ERROR",
      ErrorType::ERBControlFlowScopeError => "ERB_CONTROL_FLOW_SCOPE_ERROR",
      ErrorType::MissingERBEndTagError => "MISSING_ERB_END_TAG_ERROR",
      ErrorType::ERBMultipleBlocksInTagError => "ERB_MULTIPLE_BLOCKS_IN_TAG_ERROR",
      ErrorType::ERBCaseWithConditionsError => "ERB_CASE_WITH_CONDITIONS_ERROR",
      ErrorType::ConditionalElementMultipleTagsError => "CONDITIONAL_ELEMENT_MULTIPLE_TAGS_ERROR",
      ErrorType::ConditionalElementConditionMismatchError => "CONDITIONAL_ELEMENT_CONDITION_MISMATCH_ERROR",
      ErrorType::InvalidCommentClosingTagError => "INVALID_COMMENT_CLOSING_TAG_ERROR",
      ErrorType::OmittedClosingTagError => "OMITTED_CLOSING_TAG_ERROR",
      ErrorType::UnclosedOpenTagError => "UNCLOSED_OPEN_TAG_ERROR",
      ErrorType::UnclosedCloseTagError => "UNCLOSED_CLOSE_TAG_ERROR",
      ErrorType::UnclosedQuoteError => "UNCLOSED_QUOTE_ERROR",
      ErrorType::MissingAttributeValueError => "MISSING_ATTRIBUTE_VALUE_ERROR",
      ErrorType::UnclosedERBTagError => "UNCLOSED_ERB_TAG_ERROR",
      ErrorType::StrayERBClosingTagError => "STRAY_ERB_CLOSING_TAG_ERROR",
      ErrorType::NestedERBTagError => "NESTED_ERB_TAG_ERROR",
      ErrorType::RenderAmbiguousLocalsError => "RENDER_AMBIGUOUS_LOCALS_ERROR",
      ErrorType::RenderMissingLocalsError => "RENDER_MISSING_LOCALS_ERROR",
      ErrorType::RenderNoArgumentsError => "RENDER_NO_ARGUMENTS_ERROR",
      ErrorType::RenderConflictingPartialError => "RENDER_CONFLICTING_PARTIAL_ERROR",
      ErrorType::RenderInvalidAsOptionError => "RENDER_INVALID_AS_OPTION_ERROR",
      ErrorType::RenderObjectAndCollectionError => "RENDER_OBJECT_AND_COLLECTION_ERROR",
      ErrorType::RenderLayoutWithoutBlockError => "RENDER_LAYOUT_WITHOUT_BLOCK_ERROR",
      ErrorType::StrictLocalsPositionalArgumentError => "STRICT_LOCALS_POSITIONAL_ARGUMENT_ERROR",
      ErrorType::StrictLocalsBlockArgumentError => "STRICT_LOCALS_BLOCK_ARGUMENT_ERROR",
      ErrorType::StrictLocalsSplatArgumentError => "STRICT_LOCALS_SPLAT_ARGUMENT_ERROR",
      ErrorType::StrictLocalsMissingParenthesisError => "STRICT_LOCALS_MISSING_PARENTHESIS_ERROR",
      ErrorType::StrictLocalsDuplicateDeclarationError => "STRICT_LOCALS_DUPLICATE_DECLARATION_ERROR",
      ErrorType::VoidElementContentError => "VOID_ELEMENT_CONTENT_ERROR",
      ErrorType::DotNotationCasingError => "DOT_NOTATION_CASING_ERROR",
    }
  }
}

pub trait ErrorNode {
  fn error_type(&self) -> &str;
  fn message(&self) -> &str;
  fn location(&self) -> &Location;
  fn tree_inspect(&self) -> String;
}

#[derive(Debug, Clone)]
pub enum AnyError {
  UnexpectedError(UnexpectedError),
  UnexpectedTokenError(UnexpectedTokenError),
  MissingOpeningTagError(MissingOpeningTagError),
  MissingClosingTagError(MissingClosingTagError),
  TagNamesMismatchError(TagNamesMismatchError),
  VoidElementClosingTagError(VoidElementClosingTagError),
  UnclosedElementError(UnclosedElementError),
  RubyParseError(RubyParseError),
  ERBControlFlowScopeError(ERBControlFlowScopeError),
  MissingERBEndTagError(MissingERBEndTagError),
  ERBMultipleBlocksInTagError(ERBMultipleBlocksInTagError),
  ERBCaseWithConditionsError(ERBCaseWithConditionsError),
  ConditionalElementMultipleTagsError(ConditionalElementMultipleTagsError),
  ConditionalElementConditionMismatchError(ConditionalElementConditionMismatchError),
  InvalidCommentClosingTagError(InvalidCommentClosingTagError),
  OmittedClosingTagError(OmittedClosingTagError),
  UnclosedOpenTagError(UnclosedOpenTagError),
  UnclosedCloseTagError(UnclosedCloseTagError),
  UnclosedQuoteError(UnclosedQuoteError),
  MissingAttributeValueError(MissingAttributeValueError),
  UnclosedERBTagError(UnclosedERBTagError),
  StrayERBClosingTagError(StrayERBClosingTagError),
  NestedERBTagError(NestedERBTagError),
  RenderAmbiguousLocalsError(RenderAmbiguousLocalsError),
  RenderMissingLocalsError(RenderMissingLocalsError),
  RenderNoArgumentsError(RenderNoArgumentsError),
  RenderConflictingPartialError(RenderConflictingPartialError),
  RenderInvalidAsOptionError(RenderInvalidAsOptionError),
  RenderObjectAndCollectionError(RenderObjectAndCollectionError),
  RenderLayoutWithoutBlockError(RenderLayoutWithoutBlockError),
  StrictLocalsPositionalArgumentError(StrictLocalsPositionalArgumentError),
  StrictLocalsBlockArgumentError(StrictLocalsBlockArgumentError),
  StrictLocalsSplatArgumentError(StrictLocalsSplatArgumentError),
  StrictLocalsMissingParenthesisError(StrictLocalsMissingParenthesisError),
  StrictLocalsDuplicateDeclarationError(StrictLocalsDuplicateDeclarationError),
  VoidElementContentError(VoidElementContentError),
  DotNotationCasingError(DotNotationCasingError),
}

impl AnyError {
  pub fn error_type(&self) -> &str {
    match self {
      AnyError::UnexpectedError(e) => &e.error_type,
      AnyError::UnexpectedTokenError(e) => &e.error_type,
      AnyError::MissingOpeningTagError(e) => &e.error_type,
      AnyError::MissingClosingTagError(e) => &e.error_type,
      AnyError::TagNamesMismatchError(e) => &e.error_type,
      AnyError::VoidElementClosingTagError(e) => &e.error_type,
      AnyError::UnclosedElementError(e) => &e.error_type,
      AnyError::RubyParseError(e) => &e.error_type,
      AnyError::ERBControlFlowScopeError(e) => &e.error_type,
      AnyError::MissingERBEndTagError(e) => &e.error_type,
      AnyError::ERBMultipleBlocksInTagError(e) => &e.error_type,
      AnyError::ERBCaseWithConditionsError(e) => &e.error_type,
      AnyError::ConditionalElementMultipleTagsError(e) => &e.error_type,
      AnyError::ConditionalElementConditionMismatchError(e) => &e.error_type,
      AnyError::InvalidCommentClosingTagError(e) => &e.error_type,
      AnyError::OmittedClosingTagError(e) => &e.error_type,
      AnyError::UnclosedOpenTagError(e) => &e.error_type,
      AnyError::UnclosedCloseTagError(e) => &e.error_type,
      AnyError::UnclosedQuoteError(e) => &e.error_type,
      AnyError::MissingAttributeValueError(e) => &e.error_type,
      AnyError::UnclosedERBTagError(e) => &e.error_type,
      AnyError::StrayERBClosingTagError(e) => &e.error_type,
      AnyError::NestedERBTagError(e) => &e.error_type,
      AnyError::RenderAmbiguousLocalsError(e) => &e.error_type,
      AnyError::RenderMissingLocalsError(e) => &e.error_type,
      AnyError::RenderNoArgumentsError(e) => &e.error_type,
      AnyError::RenderConflictingPartialError(e) => &e.error_type,
      AnyError::RenderInvalidAsOptionError(e) => &e.error_type,
      AnyError::RenderObjectAndCollectionError(e) => &e.error_type,
      AnyError::RenderLayoutWithoutBlockError(e) => &e.error_type,
      AnyError::StrictLocalsPositionalArgumentError(e) => &e.error_type,
      AnyError::StrictLocalsBlockArgumentError(e) => &e.error_type,
      AnyError::StrictLocalsSplatArgumentError(e) => &e.error_type,
      AnyError::StrictLocalsMissingParenthesisError(e) => &e.error_type,
      AnyError::StrictLocalsDuplicateDeclarationError(e) => &e.error_type,
      AnyError::VoidElementContentError(e) => &e.error_type,
      AnyError::DotNotationCasingError(e) => &e.error_type,
    }
  }

  pub fn message(&self) -> &str {
    match self {
      AnyError::UnexpectedError(e) => &e.message,
      AnyError::UnexpectedTokenError(e) => &e.message,
      AnyError::MissingOpeningTagError(e) => &e.message,
      AnyError::MissingClosingTagError(e) => &e.message,
      AnyError::TagNamesMismatchError(e) => &e.message,
      AnyError::VoidElementClosingTagError(e) => &e.message,
      AnyError::UnclosedElementError(e) => &e.message,
      AnyError::RubyParseError(e) => &e.message,
      AnyError::ERBControlFlowScopeError(e) => &e.message,
      AnyError::MissingERBEndTagError(e) => &e.message,
      AnyError::ERBMultipleBlocksInTagError(e) => &e.message,
      AnyError::ERBCaseWithConditionsError(e) => &e.message,
      AnyError::ConditionalElementMultipleTagsError(e) => &e.message,
      AnyError::ConditionalElementConditionMismatchError(e) => &e.message,
      AnyError::InvalidCommentClosingTagError(e) => &e.message,
      AnyError::OmittedClosingTagError(e) => &e.message,
      AnyError::UnclosedOpenTagError(e) => &e.message,
      AnyError::UnclosedCloseTagError(e) => &e.message,
      AnyError::UnclosedQuoteError(e) => &e.message,
      AnyError::MissingAttributeValueError(e) => &e.message,
      AnyError::UnclosedERBTagError(e) => &e.message,
      AnyError::StrayERBClosingTagError(e) => &e.message,
      AnyError::NestedERBTagError(e) => &e.message,
      AnyError::RenderAmbiguousLocalsError(e) => &e.message,
      AnyError::RenderMissingLocalsError(e) => &e.message,
      AnyError::RenderNoArgumentsError(e) => &e.message,
      AnyError::RenderConflictingPartialError(e) => &e.message,
      AnyError::RenderInvalidAsOptionError(e) => &e.message,
      AnyError::RenderObjectAndCollectionError(e) => &e.message,
      AnyError::RenderLayoutWithoutBlockError(e) => &e.message,
      AnyError::StrictLocalsPositionalArgumentError(e) => &e.message,
      AnyError::StrictLocalsBlockArgumentError(e) => &e.message,
      AnyError::StrictLocalsSplatArgumentError(e) => &e.message,
      AnyError::StrictLocalsMissingParenthesisError(e) => &e.message,
      AnyError::StrictLocalsDuplicateDeclarationError(e) => &e.message,
      AnyError::VoidElementContentError(e) => &e.message,
      AnyError::DotNotationCasingError(e) => &e.message,
    }
  }

  pub fn location(&self) -> &Location {
    match self {
      AnyError::UnexpectedError(e) => &e.location,
      AnyError::UnexpectedTokenError(e) => &e.location,
      AnyError::MissingOpeningTagError(e) => &e.location,
      AnyError::MissingClosingTagError(e) => &e.location,
      AnyError::TagNamesMismatchError(e) => &e.location,
      AnyError::VoidElementClosingTagError(e) => &e.location,
      AnyError::UnclosedElementError(e) => &e.location,
      AnyError::RubyParseError(e) => &e.location,
      AnyError::ERBControlFlowScopeError(e) => &e.location,
      AnyError::MissingERBEndTagError(e) => &e.location,
      AnyError::ERBMultipleBlocksInTagError(e) => &e.location,
      AnyError::ERBCaseWithConditionsError(e) => &e.location,
      AnyError::ConditionalElementMultipleTagsError(e) => &e.location,
      AnyError::ConditionalElementConditionMismatchError(e) => &e.location,
      AnyError::InvalidCommentClosingTagError(e) => &e.location,
      AnyError::OmittedClosingTagError(e) => &e.location,
      AnyError::UnclosedOpenTagError(e) => &e.location,
      AnyError::UnclosedCloseTagError(e) => &e.location,
      AnyError::UnclosedQuoteError(e) => &e.location,
      AnyError::MissingAttributeValueError(e) => &e.location,
      AnyError::UnclosedERBTagError(e) => &e.location,
      AnyError::StrayERBClosingTagError(e) => &e.location,
      AnyError::NestedERBTagError(e) => &e.location,
      AnyError::RenderAmbiguousLocalsError(e) => &e.location,
      AnyError::RenderMissingLocalsError(e) => &e.location,
      AnyError::RenderNoArgumentsError(e) => &e.location,
      AnyError::RenderConflictingPartialError(e) => &e.location,
      AnyError::RenderInvalidAsOptionError(e) => &e.location,
      AnyError::RenderObjectAndCollectionError(e) => &e.location,
      AnyError::RenderLayoutWithoutBlockError(e) => &e.location,
      AnyError::StrictLocalsPositionalArgumentError(e) => &e.location,
      AnyError::StrictLocalsBlockArgumentError(e) => &e.location,
      AnyError::StrictLocalsSplatArgumentError(e) => &e.location,
      AnyError::StrictLocalsMissingParenthesisError(e) => &e.location,
      AnyError::StrictLocalsDuplicateDeclarationError(e) => &e.location,
      AnyError::VoidElementContentError(e) => &e.location,
      AnyError::DotNotationCasingError(e) => &e.location,
    }
  }

  pub fn tree_inspect(&self) -> String {
    match self {
      AnyError::UnexpectedError(e) => e.tree_inspect(),
      AnyError::UnexpectedTokenError(e) => e.tree_inspect(),
      AnyError::MissingOpeningTagError(e) => e.tree_inspect(),
      AnyError::MissingClosingTagError(e) => e.tree_inspect(),
      AnyError::TagNamesMismatchError(e) => e.tree_inspect(),
      AnyError::VoidElementClosingTagError(e) => e.tree_inspect(),
      AnyError::UnclosedElementError(e) => e.tree_inspect(),
      AnyError::RubyParseError(e) => e.tree_inspect(),
      AnyError::ERBControlFlowScopeError(e) => e.tree_inspect(),
      AnyError::MissingERBEndTagError(e) => e.tree_inspect(),
      AnyError::ERBMultipleBlocksInTagError(e) => e.tree_inspect(),
      AnyError::ERBCaseWithConditionsError(e) => e.tree_inspect(),
      AnyError::ConditionalElementMultipleTagsError(e) => e.tree_inspect(),
      AnyError::ConditionalElementConditionMismatchError(e) => e.tree_inspect(),
      AnyError::InvalidCommentClosingTagError(e) => e.tree_inspect(),
      AnyError::OmittedClosingTagError(e) => e.tree_inspect(),
      AnyError::UnclosedOpenTagError(e) => e.tree_inspect(),
      AnyError::UnclosedCloseTagError(e) => e.tree_inspect(),
      AnyError::UnclosedQuoteError(e) => e.tree_inspect(),
      AnyError::MissingAttributeValueError(e) => e.tree_inspect(),
      AnyError::UnclosedERBTagError(e) => e.tree_inspect(),
      AnyError::StrayERBClosingTagError(e) => e.tree_inspect(),
      AnyError::NestedERBTagError(e) => e.tree_inspect(),
      AnyError::RenderAmbiguousLocalsError(e) => e.tree_inspect(),
      AnyError::RenderMissingLocalsError(e) => e.tree_inspect(),
      AnyError::RenderNoArgumentsError(e) => e.tree_inspect(),
      AnyError::RenderConflictingPartialError(e) => e.tree_inspect(),
      AnyError::RenderInvalidAsOptionError(e) => e.tree_inspect(),
      AnyError::RenderObjectAndCollectionError(e) => e.tree_inspect(),
      AnyError::RenderLayoutWithoutBlockError(e) => e.tree_inspect(),
      AnyError::StrictLocalsPositionalArgumentError(e) => e.tree_inspect(),
      AnyError::StrictLocalsBlockArgumentError(e) => e.tree_inspect(),
      AnyError::StrictLocalsSplatArgumentError(e) => e.tree_inspect(),
      AnyError::StrictLocalsMissingParenthesisError(e) => e.tree_inspect(),
      AnyError::StrictLocalsDuplicateDeclarationError(e) => e.tree_inspect(),
      AnyError::VoidElementContentError(e) => e.tree_inspect(),
      AnyError::DotNotationCasingError(e) => e.tree_inspect(),
    }
  }
}

impl ErrorNode for AnyError {
  fn error_type(&self) -> &str {
    self.error_type()
  }

  fn message(&self) -> &str {
    self.message()
  }

  fn location(&self) -> &Location {
    self.location()
  }

  fn tree_inspect(&self) -> String {
    self.tree_inspect()
  }
}

#[derive(Debug, Clone)]
pub struct UnexpectedError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub description: String,
  pub expected: String,
  pub found: String,
}

#[allow(clippy::too_many_arguments)]
impl UnexpectedError {
  pub fn new(
    message: String,
    location: Location,
    description: String,
    expected: String,
    found: String,
  ) -> Self {
    Self {
      error_type: "UNEXPECTED_ERROR".to_string(),
      message,
      location,
      description,
      expected,
      found,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "UnexpectedError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "description".white(), format_string_value(&self.description)));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "expected".white(), format_string_value(&self.expected)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "found".white(), format_string_value(&self.found)));

    output
  }
}

impl ErrorNode for UnexpectedError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    UnexpectedError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct UnexpectedTokenError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub expected_type: Option<String>,
  pub found: Option<Token>,
}

#[allow(clippy::too_many_arguments)]
impl UnexpectedTokenError {
  pub fn new(
    message: String,
    location: Location,
    expected_type: Option<String>,
    found: Option<Token>,
  ) -> Self {
    Self {
      error_type: "UNEXPECTED_TOKEN_ERROR".to_string(),
      message,
      location,
      expected_type,
      found,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "UnexpectedTokenError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "expected_type".white(), format_token_type_value(&self.expected_type)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "found".white(), format_token_value(&self.found)));

    output
  }
}

impl ErrorNode for UnexpectedTokenError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    UnexpectedTokenError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct MissingOpeningTagError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub closing_tag: Option<Token>,
}

#[allow(clippy::too_many_arguments)]
impl MissingOpeningTagError {
  pub fn new(
    message: String,
    location: Location,
    closing_tag: Option<Token>,
  ) -> Self {
    Self {
      error_type: "MISSING_OPENING_TAG_ERROR".to_string(),
      message,
      location,
      closing_tag,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "MissingOpeningTagError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "closing_tag".white(), format_token_value(&self.closing_tag)));

    output
  }
}

impl ErrorNode for MissingOpeningTagError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    MissingOpeningTagError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct MissingClosingTagError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub opening_tag: Option<Token>,
}

#[allow(clippy::too_many_arguments)]
impl MissingClosingTagError {
  pub fn new(
    message: String,
    location: Location,
    opening_tag: Option<Token>,
  ) -> Self {
    Self {
      error_type: "MISSING_CLOSING_TAG_ERROR".to_string(),
      message,
      location,
      opening_tag,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "MissingClosingTagError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "opening_tag".white(), format_token_value(&self.opening_tag)));

    output
  }
}

impl ErrorNode for MissingClosingTagError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    MissingClosingTagError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct TagNamesMismatchError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub opening_tag: Option<Token>,
  pub closing_tag: Option<Token>,
}

#[allow(clippy::too_many_arguments)]
impl TagNamesMismatchError {
  pub fn new(
    message: String,
    location: Location,
    opening_tag: Option<Token>,
    closing_tag: Option<Token>,
  ) -> Self {
    Self {
      error_type: "TAG_NAMES_MISMATCH_ERROR".to_string(),
      message,
      location,
      opening_tag,
      closing_tag,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "TagNamesMismatchError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "opening_tag".white(), format_token_value(&self.opening_tag)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "closing_tag".white(), format_token_value(&self.closing_tag)));

    output
  }
}

impl ErrorNode for TagNamesMismatchError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    TagNamesMismatchError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct VoidElementClosingTagError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub tag_name: Option<Token>,
  pub expected: String,
  pub found: String,
}

#[allow(clippy::too_many_arguments)]
impl VoidElementClosingTagError {
  pub fn new(
    message: String,
    location: Location,
    tag_name: Option<Token>,
    expected: String,
    found: String,
  ) -> Self {
    Self {
      error_type: "VOID_ELEMENT_CLOSING_TAG_ERROR".to_string(),
      message,
      location,
      tag_name,
      expected,
      found,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "VoidElementClosingTagError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "tag_name".white(), format_token_value(&self.tag_name)));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "expected".white(), format_string_value(&self.expected)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "found".white(), format_string_value(&self.found)));

    output
  }
}

impl ErrorNode for VoidElementClosingTagError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    VoidElementClosingTagError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct UnclosedElementError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub opening_tag: Option<Token>,
}

#[allow(clippy::too_many_arguments)]
impl UnclosedElementError {
  pub fn new(
    message: String,
    location: Location,
    opening_tag: Option<Token>,
  ) -> Self {
    Self {
      error_type: "UNCLOSED_ELEMENT_ERROR".to_string(),
      message,
      location,
      opening_tag,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "UnclosedElementError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "opening_tag".white(), format_token_value(&self.opening_tag)));

    output
  }
}

impl ErrorNode for UnclosedElementError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    UnclosedElementError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct RubyParseError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub error_message: String,
  pub diagnostic_id: String,
  pub level: String,
}

#[allow(clippy::too_many_arguments)]
impl RubyParseError {
  pub fn new(
    message: String,
    location: Location,
    error_message: String,
    diagnostic_id: String,
    level: String,
  ) -> Self {
    Self {
      error_type: "RUBY_PARSE_ERROR".to_string(),
      message,
      location,
      error_message,
      diagnostic_id,
      level,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "RubyParseError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "error_message".white(), format_string_value(&self.error_message)));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "diagnostic_id".white(), format_string_value(&self.diagnostic_id)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "level".white(), format_string_value(&self.level)));

    output
  }
}

impl ErrorNode for RubyParseError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    RubyParseError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct ERBControlFlowScopeError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub keyword: String,
}

#[allow(clippy::too_many_arguments)]
impl ERBControlFlowScopeError {
  pub fn new(
    message: String,
    location: Location,
    keyword: String,
  ) -> Self {
    Self {
      error_type: "ERB_CONTROL_FLOW_SCOPE_ERROR".to_string(),
      message,
      location,
      keyword,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "ERBControlFlowScopeError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "keyword".white(), format_string_value(&self.keyword)));

    output
  }
}

impl ErrorNode for ERBControlFlowScopeError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    ERBControlFlowScopeError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct MissingERBEndTagError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub keyword: String,
}

#[allow(clippy::too_many_arguments)]
impl MissingERBEndTagError {
  pub fn new(
    message: String,
    location: Location,
    keyword: String,
  ) -> Self {
    Self {
      error_type: "MISSING_ERB_END_TAG_ERROR".to_string(),
      message,
      location,
      keyword,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "MissingERBEndTagError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "keyword".white(), format_string_value(&self.keyword)));

    output
  }
}

impl ErrorNode for MissingERBEndTagError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    MissingERBEndTagError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct ERBMultipleBlocksInTagError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
}

#[allow(clippy::too_many_arguments)]
impl ERBMultipleBlocksInTagError {
  pub fn new(
    message: String,
    location: Location,
  ) -> Self {
    Self {
      error_type: "ERB_MULTIPLE_BLOCKS_IN_TAG_ERROR".to_string(),
      message,
      location,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "ERBMultipleBlocksInTagError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "message".white(), format_string_value(&self.message)));

    output
  }
}

impl ErrorNode for ERBMultipleBlocksInTagError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    ERBMultipleBlocksInTagError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct ERBCaseWithConditionsError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
}

#[allow(clippy::too_many_arguments)]
impl ERBCaseWithConditionsError {
  pub fn new(
    message: String,
    location: Location,
  ) -> Self {
    Self {
      error_type: "ERB_CASE_WITH_CONDITIONS_ERROR".to_string(),
      message,
      location,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "ERBCaseWithConditionsError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "message".white(), format_string_value(&self.message)));

    output
  }
}

impl ErrorNode for ERBCaseWithConditionsError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    ERBCaseWithConditionsError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct ConditionalElementMultipleTagsError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub line: usize,
  pub column: usize,
}

#[allow(clippy::too_many_arguments)]
impl ConditionalElementMultipleTagsError {
  pub fn new(
    message: String,
    location: Location,
    line: usize,
    column: usize,
  ) -> Self {
    Self {
      error_type: "CONDITIONAL_ELEMENT_MULTIPLE_TAGS_ERROR".to_string(),
      message,
      location,
      line,
      column,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "ConditionalElementMultipleTagsError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "line".white(), format_size_value(self.line)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "column".white(), format_size_value(self.column)));

    output
  }
}

impl ErrorNode for ConditionalElementMultipleTagsError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    ConditionalElementMultipleTagsError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct ConditionalElementConditionMismatchError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub tag_name: String,
  pub open_condition: String,
  pub open_line: usize,
  pub open_column: usize,
  pub close_condition: String,
  pub close_line: usize,
  pub close_column: usize,
}

#[allow(clippy::too_many_arguments)]
impl ConditionalElementConditionMismatchError {
  pub fn new(
    message: String,
    location: Location,
    tag_name: String,
    open_condition: String,
    open_line: usize,
    open_column: usize,
    close_condition: String,
    close_line: usize,
    close_column: usize,
  ) -> Self {
    Self {
      error_type: "CONDITIONAL_ELEMENT_CONDITION_MISMATCH_ERROR".to_string(),
      message,
      location,
      tag_name,
      open_condition,
      open_line,
      open_column,
      close_condition,
      close_line,
      close_column,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "ConditionalElementConditionMismatchError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "tag_name".white(), format_string_value(&self.tag_name)));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "open_condition".white(), format_string_value(&self.open_condition)));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "open_line".white(), format_size_value(self.open_line)));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "open_column".white(), format_size_value(self.open_column)));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "close_condition".white(), format_string_value(&self.close_condition)));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "close_line".white(), format_size_value(self.close_line)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "close_column".white(), format_size_value(self.close_column)));

    output
  }
}

impl ErrorNode for ConditionalElementConditionMismatchError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    ConditionalElementConditionMismatchError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct InvalidCommentClosingTagError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub closing_tag: Option<Token>,
}

#[allow(clippy::too_many_arguments)]
impl InvalidCommentClosingTagError {
  pub fn new(
    message: String,
    location: Location,
    closing_tag: Option<Token>,
  ) -> Self {
    Self {
      error_type: "INVALID_COMMENT_CLOSING_TAG_ERROR".to_string(),
      message,
      location,
      closing_tag,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "InvalidCommentClosingTagError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "closing_tag".white(), format_token_value(&self.closing_tag)));

    output
  }
}

impl ErrorNode for InvalidCommentClosingTagError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    InvalidCommentClosingTagError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct OmittedClosingTagError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub opening_tag: Option<Token>,
  pub insertion_point: Option<Position>,
}

#[allow(clippy::too_many_arguments)]
impl OmittedClosingTagError {
  pub fn new(
    message: String,
    location: Location,
    opening_tag: Option<Token>,
    insertion_point: Option<Position>,
  ) -> Self {
    Self {
      error_type: "OMITTED_CLOSING_TAG_ERROR".to_string(),
      message,
      location,
      opening_tag,
      insertion_point,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "OmittedClosingTagError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "opening_tag".white(), format_token_value(&self.opening_tag)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "insertion_point".white(), format_position_value(&self.insertion_point)));

    output
  }
}

impl ErrorNode for OmittedClosingTagError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    OmittedClosingTagError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct UnclosedOpenTagError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub tag_name: Option<Token>,
}

#[allow(clippy::too_many_arguments)]
impl UnclosedOpenTagError {
  pub fn new(
    message: String,
    location: Location,
    tag_name: Option<Token>,
  ) -> Self {
    Self {
      error_type: "UNCLOSED_OPEN_TAG_ERROR".to_string(),
      message,
      location,
      tag_name,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "UnclosedOpenTagError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "tag_name".white(), format_token_value(&self.tag_name)));

    output
  }
}

impl ErrorNode for UnclosedOpenTagError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    UnclosedOpenTagError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct UnclosedCloseTagError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub tag_name: Option<Token>,
}

#[allow(clippy::too_many_arguments)]
impl UnclosedCloseTagError {
  pub fn new(
    message: String,
    location: Location,
    tag_name: Option<Token>,
  ) -> Self {
    Self {
      error_type: "UNCLOSED_CLOSE_TAG_ERROR".to_string(),
      message,
      location,
      tag_name,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "UnclosedCloseTagError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "tag_name".white(), format_token_value(&self.tag_name)));

    output
  }
}

impl ErrorNode for UnclosedCloseTagError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    UnclosedCloseTagError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct UnclosedQuoteError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub opening_quote: Option<Token>,
}

#[allow(clippy::too_many_arguments)]
impl UnclosedQuoteError {
  pub fn new(
    message: String,
    location: Location,
    opening_quote: Option<Token>,
  ) -> Self {
    Self {
      error_type: "UNCLOSED_QUOTE_ERROR".to_string(),
      message,
      location,
      opening_quote,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "UnclosedQuoteError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "opening_quote".white(), format_token_value(&self.opening_quote)));

    output
  }
}

impl ErrorNode for UnclosedQuoteError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    UnclosedQuoteError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct MissingAttributeValueError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub attribute_name: String,
}

#[allow(clippy::too_many_arguments)]
impl MissingAttributeValueError {
  pub fn new(
    message: String,
    location: Location,
    attribute_name: String,
  ) -> Self {
    Self {
      error_type: "MISSING_ATTRIBUTE_VALUE_ERROR".to_string(),
      message,
      location,
      attribute_name,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "MissingAttributeValueError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "attribute_name".white(), format_string_value(&self.attribute_name)));

    output
  }
}

impl ErrorNode for MissingAttributeValueError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    MissingAttributeValueError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct UnclosedERBTagError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub opening_tag: Option<Token>,
}

#[allow(clippy::too_many_arguments)]
impl UnclosedERBTagError {
  pub fn new(
    message: String,
    location: Location,
    opening_tag: Option<Token>,
  ) -> Self {
    Self {
      error_type: "UNCLOSED_ERB_TAG_ERROR".to_string(),
      message,
      location,
      opening_tag,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "UnclosedERBTagError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "opening_tag".white(), format_token_value(&self.opening_tag)));

    output
  }
}

impl ErrorNode for UnclosedERBTagError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    UnclosedERBTagError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct StrayERBClosingTagError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
}

#[allow(clippy::too_many_arguments)]
impl StrayERBClosingTagError {
  pub fn new(
    message: String,
    location: Location,
  ) -> Self {
    Self {
      error_type: "STRAY_ERB_CLOSING_TAG_ERROR".to_string(),
      message,
      location,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "StrayERBClosingTagError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "message".white(), format_string_value(&self.message)));

    output
  }
}

impl ErrorNode for StrayERBClosingTagError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    StrayERBClosingTagError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct NestedERBTagError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub opening_tag: Option<Token>,
  pub nested_tag_line: usize,
  pub nested_tag_column: usize,
}

#[allow(clippy::too_many_arguments)]
impl NestedERBTagError {
  pub fn new(
    message: String,
    location: Location,
    opening_tag: Option<Token>,
    nested_tag_line: usize,
    nested_tag_column: usize,
  ) -> Self {
    Self {
      error_type: "NESTED_ERB_TAG_ERROR".to_string(),
      message,
      location,
      opening_tag,
      nested_tag_line,
      nested_tag_column,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "NestedERBTagError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "opening_tag".white(), format_token_value(&self.opening_tag)));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "nested_tag_line".white(), format_size_value(self.nested_tag_line)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "nested_tag_column".white(), format_size_value(self.nested_tag_column)));

    output
  }
}

impl ErrorNode for NestedERBTagError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    NestedERBTagError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct RenderAmbiguousLocalsError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub partial: String,
}

#[allow(clippy::too_many_arguments)]
impl RenderAmbiguousLocalsError {
  pub fn new(
    message: String,
    location: Location,
    partial: String,
  ) -> Self {
    Self {
      error_type: "RENDER_AMBIGUOUS_LOCALS_ERROR".to_string(),
      message,
      location,
      partial,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "RenderAmbiguousLocalsError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "partial".white(), format_string_value(&self.partial)));

    output
  }
}

impl ErrorNode for RenderAmbiguousLocalsError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    RenderAmbiguousLocalsError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct RenderMissingLocalsError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub partial: String,
  pub keywords: String,
}

#[allow(clippy::too_many_arguments)]
impl RenderMissingLocalsError {
  pub fn new(
    message: String,
    location: Location,
    partial: String,
    keywords: String,
  ) -> Self {
    Self {
      error_type: "RENDER_MISSING_LOCALS_ERROR".to_string(),
      message,
      location,
      partial,
      keywords,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "RenderMissingLocalsError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "partial".white(), format_string_value(&self.partial)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "keywords".white(), format_string_value(&self.keywords)));

    output
  }
}

impl ErrorNode for RenderMissingLocalsError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    RenderMissingLocalsError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct RenderNoArgumentsError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
}

#[allow(clippy::too_many_arguments)]
impl RenderNoArgumentsError {
  pub fn new(
    message: String,
    location: Location,
  ) -> Self {
    Self {
      error_type: "RENDER_NO_ARGUMENTS_ERROR".to_string(),
      message,
      location,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "RenderNoArgumentsError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "message".white(), format_string_value(&self.message)));

    output
  }
}

impl ErrorNode for RenderNoArgumentsError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    RenderNoArgumentsError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct RenderConflictingPartialError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub positional_partial: String,
  pub keyword_partial: String,
}

#[allow(clippy::too_many_arguments)]
impl RenderConflictingPartialError {
  pub fn new(
    message: String,
    location: Location,
    positional_partial: String,
    keyword_partial: String,
  ) -> Self {
    Self {
      error_type: "RENDER_CONFLICTING_PARTIAL_ERROR".to_string(),
      message,
      location,
      positional_partial,
      keyword_partial,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "RenderConflictingPartialError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "positional_partial".white(), format_string_value(&self.positional_partial)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "keyword_partial".white(), format_string_value(&self.keyword_partial)));

    output
  }
}

impl ErrorNode for RenderConflictingPartialError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    RenderConflictingPartialError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct RenderInvalidAsOptionError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub as_value: String,
}

#[allow(clippy::too_many_arguments)]
impl RenderInvalidAsOptionError {
  pub fn new(
    message: String,
    location: Location,
    as_value: String,
  ) -> Self {
    Self {
      error_type: "RENDER_INVALID_AS_OPTION_ERROR".to_string(),
      message,
      location,
      as_value,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "RenderInvalidAsOptionError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "as_value".white(), format_string_value(&self.as_value)));

    output
  }
}

impl ErrorNode for RenderInvalidAsOptionError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    RenderInvalidAsOptionError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct RenderObjectAndCollectionError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
}

#[allow(clippy::too_many_arguments)]
impl RenderObjectAndCollectionError {
  pub fn new(
    message: String,
    location: Location,
  ) -> Self {
    Self {
      error_type: "RENDER_OBJECT_AND_COLLECTION_ERROR".to_string(),
      message,
      location,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "RenderObjectAndCollectionError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "message".white(), format_string_value(&self.message)));

    output
  }
}

impl ErrorNode for RenderObjectAndCollectionError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    RenderObjectAndCollectionError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct RenderLayoutWithoutBlockError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub layout: String,
}

#[allow(clippy::too_many_arguments)]
impl RenderLayoutWithoutBlockError {
  pub fn new(
    message: String,
    location: Location,
    layout: String,
  ) -> Self {
    Self {
      error_type: "RENDER_LAYOUT_WITHOUT_BLOCK_ERROR".to_string(),
      message,
      location,
      layout,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "RenderLayoutWithoutBlockError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "layout".white(), format_string_value(&self.layout)));

    output
  }
}

impl ErrorNode for RenderLayoutWithoutBlockError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    RenderLayoutWithoutBlockError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct StrictLocalsPositionalArgumentError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub name: String,
}

#[allow(clippy::too_many_arguments)]
impl StrictLocalsPositionalArgumentError {
  pub fn new(
    message: String,
    location: Location,
    name: String,
  ) -> Self {
    Self {
      error_type: "STRICT_LOCALS_POSITIONAL_ARGUMENT_ERROR".to_string(),
      message,
      location,
      name,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "StrictLocalsPositionalArgumentError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "name".white(), format_string_value(&self.name)));

    output
  }
}

impl ErrorNode for StrictLocalsPositionalArgumentError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    StrictLocalsPositionalArgumentError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct StrictLocalsBlockArgumentError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub name: String,
}

#[allow(clippy::too_many_arguments)]
impl StrictLocalsBlockArgumentError {
  pub fn new(
    message: String,
    location: Location,
    name: String,
  ) -> Self {
    Self {
      error_type: "STRICT_LOCALS_BLOCK_ARGUMENT_ERROR".to_string(),
      message,
      location,
      name,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "StrictLocalsBlockArgumentError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "name".white(), format_string_value(&self.name)));

    output
  }
}

impl ErrorNode for StrictLocalsBlockArgumentError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    StrictLocalsBlockArgumentError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct StrictLocalsSplatArgumentError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub name: String,
}

#[allow(clippy::too_many_arguments)]
impl StrictLocalsSplatArgumentError {
  pub fn new(
    message: String,
    location: Location,
    name: String,
  ) -> Self {
    Self {
      error_type: "STRICT_LOCALS_SPLAT_ARGUMENT_ERROR".to_string(),
      message,
      location,
      name,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "StrictLocalsSplatArgumentError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "name".white(), format_string_value(&self.name)));

    output
  }
}

impl ErrorNode for StrictLocalsSplatArgumentError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    StrictLocalsSplatArgumentError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct StrictLocalsMissingParenthesisError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub rest: String,
}

#[allow(clippy::too_many_arguments)]
impl StrictLocalsMissingParenthesisError {
  pub fn new(
    message: String,
    location: Location,
    rest: String,
  ) -> Self {
    Self {
      error_type: "STRICT_LOCALS_MISSING_PARENTHESIS_ERROR".to_string(),
      message,
      location,
      rest,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "StrictLocalsMissingParenthesisError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "rest".white(), format_string_value(&self.rest)));

    output
  }
}

impl ErrorNode for StrictLocalsMissingParenthesisError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    StrictLocalsMissingParenthesisError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct StrictLocalsDuplicateDeclarationError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
}

#[allow(clippy::too_many_arguments)]
impl StrictLocalsDuplicateDeclarationError {
  pub fn new(
    message: String,
    location: Location,
  ) -> Self {
    Self {
      error_type: "STRICT_LOCALS_DUPLICATE_DECLARATION_ERROR".to_string(),
      message,
      location,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "StrictLocalsDuplicateDeclarationError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "message".white(), format_string_value(&self.message)));

    output
  }
}

impl ErrorNode for StrictLocalsDuplicateDeclarationError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    StrictLocalsDuplicateDeclarationError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct VoidElementContentError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub tag_name: Option<Token>,
  pub helper_name: String,
  pub content_type: String,
}

#[allow(clippy::too_many_arguments)]
impl VoidElementContentError {
  pub fn new(
    message: String,
    location: Location,
    tag_name: Option<Token>,
    helper_name: String,
    content_type: String,
  ) -> Self {
    Self {
      error_type: "VOID_ELEMENT_CONTENT_ERROR".to_string(),
      message,
      location,
      tag_name,
      helper_name,
      content_type,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "VoidElementContentError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "tag_name".white(), format_token_value(&self.tag_name)));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "helper_name".white(), format_string_value(&self.helper_name)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "content_type".white(), format_string_value(&self.content_type)));

    output
  }
}

impl ErrorNode for VoidElementContentError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    VoidElementContentError::tree_inspect(self)
  }
}

#[derive(Debug, Clone)]
pub struct DotNotationCasingError {
  pub error_type: String,
  pub message: String,
  pub location: Location,
  pub segment: Option<Token>,
}

#[allow(clippy::too_many_arguments)]
impl DotNotationCasingError {
  pub fn new(
    message: String,
    location: Location,
    segment: Option<Token>,
  ) -> Self {
    Self {
      error_type: "DOT_NOTATION_CASING_ERROR".to_string(),
      message,
      location,
      segment,
    }
  }

  pub fn tree_inspect(&self) -> String {
    let mut output = String::new();

    output.push_str(&format!("{} {} {}\n",
      "@".white(),
      "DotNotationCasingError".red().bold(),
      format!("(location: {})", self.location).dimmed()
    ));
    output.push_str(&format!("{} {}: {}\n", "├──".white(), "message".white(), format_string_value(&self.message)));
    output.push_str(&format!("{} {}: {}\n", "└──".white(), "segment".white(), format_token_value(&self.segment)));

    output
  }
}

impl ErrorNode for DotNotationCasingError {
  fn error_type(&self) -> &str {
    &self.error_type
  }

  fn message(&self) -> &str {
    &self.message
  }

  fn location(&self) -> &Location {
    &self.location
  }

  fn tree_inspect(&self) -> String {
    DotNotationCasingError::tree_inspect(self)
  }
}

