skymark 0.1.1

HTML-to-Markdown converter prioritizing proper conversion for human readability
Documentation
use std::collections::HashMap;

/// Newlines added around a translated node.
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub enum SurroundingNewlines {
    /// No surrounding newlines.
    #[default]
    None,
    /// Add this many surrounding newlines.
    Count(usize),
}

/// Static translator configuration for one or more tags.
#[derive(Clone, Debug, Default)]
pub struct TranslatorConfig {
    /// Prefix written before translated content.
    pub prefix: Option<String>,
    /// Postfix written after translated content.
    pub postfix: Option<String>,
    /// Fixed content for the node.
    pub content: Option<String>,
    /// Whether to recurse into children.
    pub recurse: Option<bool>,
    /// Surrounding newline policy.
    pub surrounding_newlines: SurroundingNewlines,
    /// Ignore this node entirely.
    pub ignore: bool,
    /// Disable escaping for this node.
    pub no_escape: bool,
    /// Insert a space if the next content repeats the current trailing delimiter char.
    pub space_if_repeating_char: bool,
    /// Preserve empty nodes during optimization.
    pub preserve_if_empty: bool,
    /// Preserve whitespace exactly.
    pub preserve_whitespace: bool,
}

#[derive(Clone, Debug, Default)]
pub(crate) struct TranslatorCollection {
    entries: HashMap<String, TranslatorConfig>,
}

impl TranslatorCollection {
    pub(crate) fn set(&mut self, keys: &str, config: &TranslatorConfig, preserve_base: bool) {
        for key in keys.split(',') {
            let normalized = key.trim().to_ascii_uppercase();
            let merged = if preserve_base {
                self.entries
                    .get(&normalized)
                    .cloned()
                    .map(|base| base.merge(config.clone()))
                    .unwrap_or_else(|| config.clone())
            } else {
                config.clone()
            };
            self.entries.insert(normalized, merged);
        }
    }

    pub(crate) fn get(&self, key: &str) -> Option<&TranslatorConfig> {
        self.entries.get(&key.to_ascii_uppercase())
    }
}

impl TranslatorConfig {
    fn merge(mut self, other: Self) -> Self {
        if other.prefix.is_some() {
            self.prefix = other.prefix;
        }
        if other.postfix.is_some() {
            self.postfix = other.postfix;
        }
        if other.content.is_some() {
            self.content = other.content;
        }
        if other.recurse.is_some() {
            self.recurse = other.recurse;
        }
        if other.surrounding_newlines != SurroundingNewlines::None {
            self.surrounding_newlines = other.surrounding_newlines;
        }
        self.ignore |= other.ignore;
        self.no_escape |= other.no_escape;
        self.space_if_repeating_char |= other.space_if_repeating_char;
        self.preserve_if_empty |= other.preserve_if_empty;
        self.preserve_whitespace |= other.preserve_whitespace;
        self
    }
}