decomment 0.2.0

Remove comments from source text in 13 languages without touching strings, templates, or regex literals.
Documentation
use crate::language::Language;

/// Which comments to remove.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
pub enum Mode {
    /// Line and block comments.
    #[default]
    All,
    /// Line comments only. Block comment text stays and is not scanned for line
    /// comments, because a `//` inside a block comment is not a line comment.
    Line,
    /// Block comments only. Line comment text stays and is not scanned for
    /// block comments.
    Block,
    /// The first comment the other settings would remove, and nothing after it.
    /// The rest of the input is copied through unchanged, comments included.
    ///
    /// The scan stops at that comment, so a construct that opens after it is
    /// never read. See [`crate::Stripped::unterminated`].
    First,
}

/// Settings for one [`crate::strip`] call.
///
/// Build with [`Options::new`] and assign the fields you want. The struct is
/// `#[non_exhaustive]`, so adding a setting later is not a breaking change.
///
/// # Examples
///
/// ```
/// use decomment::{strip, Language, Mode, Options};
///
/// let mut options = Options::new(Language::Rust);
/// options.mode = Mode::Line;
/// assert_eq!(strip("let x = 1; // note", options).output, "let x = 1; ");
/// ```
#[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Options {
    /// Which comment and literal grammar to scan with.
    pub language: Language,
    /// Which comments to remove.
    pub mode: Mode,
    /// Emit the line terminators that sat inside removed text, byte for byte.
    /// CRLF stays CRLF. Line comments are unaffected, because their terminator
    /// is never part of the comment.
    pub preserve_newlines: bool,
    /// Keep a comment whose body starts with `!`.
    ///
    /// The body starts at the byte after the opening marker, so `//!`, `/*!`,
    /// `<!--!`, `--!`, and `#!` all qualify and `///` does not. This keeps
    /// minifier license banners and keeps a `#!` shebang line in Python.
    ///
    /// In Rust, `//!` is an inner doc comment rather than a banner. With this
    /// flag set and [`Language::Rust`], inner doc comments survive and outer
    /// `///` doc comments do not.
    pub keep_bang_comments: bool,
}

impl Options {
    /// Default settings for a language: [`Mode::All`] with both flags off.
    ///
    /// # Examples
    ///
    /// ```
    /// use decomment::{Language, Mode, Options};
    ///
    /// let options = Options::new(Language::Css);
    /// assert_eq!(options.mode, Mode::All);
    /// assert_eq!(options.preserve_newlines, false);
    /// assert_eq!(options.keep_bang_comments, false);
    /// ```
    #[must_use]
    pub const fn new(language: Language) -> Options {
        Options {
            language,
            mode: Mode::All,
            preserve_newlines: false,
            keep_bang_comments: false,
        }
    }
}