decomment 0.2.0

Remove comments from source text in 13 languages without touching strings, templates, or regex literals.
Documentation
/// Comment and literal syntax to scan with.
///
/// Every variant is a distinct scanning configuration. `TypeScript` is the one
/// exception: it is a deliberate alias of `JavaScript`, because the two share a
/// comment and literal grammar.
#[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum Language {
    /// `//`, `/* */`, double and single quoted strings.
    C,
    /// C plus raw strings written `R"delim( ... )delim"`.
    Cpp,
    /// C plus verbatim strings written `@"..."`, where `""` is an escaped quote.
    CSharp,
    /// `/* */` only. `//` is not a comment in CSS.
    Css,
    /// C plus raw backtick strings, which have no escapes.
    Go,
    /// `<!-- -->` only. Quotes have no special meaning.
    Html,
    /// C plus text blocks written `"""`.
    Java,
    /// C plus templates with `${}` nesting and regex literals.
    JavaScript,
    /// `#` only. No block comment form. Quote prefixes such as `r` and `f`.
    Python,
    /// `//`, nesting `/* */`, raw strings, byte strings, and the lifetime rule.
    Rust,
    /// `--`, `/* */`, and quotes where a doubled quote is an escaped quote.
    Sql,
    /// `//`, nesting `/* */`, `"""`, and raw strings written `#"..."#`.
    Swift,
    /// Identical to [`Language::JavaScript`].
    TypeScript,
}

/// The scanning table for one language.
///
/// Built once per [`crate::strip`] call. The scan loop reads these fields and
/// never matches on [`Language`] again.
#[derive(Clone, Copy)]
pub(crate) struct Syntax {
    /// Line comment opener.
    pub line: Option<&'static [u8]>,
    /// Block comment opener and closer.
    pub block: Option<(&'static [u8], &'static [u8])>,
    /// Block comments nest.
    pub nests: bool,
    /// `"` opens a string.
    pub double_quote: bool,
    /// `'` opens a string or character literal.
    pub single_quote: bool,
    /// `"""` opens a multi-line string.
    pub triple_double: bool,
    /// `'''` opens a multi-line string.
    pub triple_single: bool,
    /// Templates, regex literals, and U+2028 or U+2029 as line terminators.
    pub js: bool,
    /// Backtick opens a raw string with no escapes.
    pub go_raw: bool,
    /// `r"`, `r#"`, `b"`, `br#"` prefixes, multi-line `"`, and the lifetime rule.
    pub rust: bool,
    /// `#"..."#` and `##"..."##` raw strings.
    pub swift_raw: bool,
    /// `R"delim( ... )delim"` raw strings.
    pub cpp_raw: bool,
    /// `@"..."` verbatim strings.
    pub csharp_verbatim: bool,
    /// One or two letter quote prefixes, where `r` or `R` disables escapes.
    pub python_prefix: bool,
    /// A doubled quote is an escaped quote and backslash is an ordinary byte.
    pub sql: bool,
}

/// No comments and no string forms. Every row starts here and turns on what it has.
const NONE: Syntax = Syntax {
    line: None,
    block: None,
    nests: false,
    double_quote: false,
    single_quote: false,
    triple_double: false,
    triple_single: false,
    js: false,
    go_raw: false,
    rust: false,
    swift_raw: false,
    cpp_raw: false,
    csharp_verbatim: false,
    python_prefix: false,
    sql: false,
};

const SLASHES: Option<&[u8]> = Some(b"//");
const SLASH_STAR: Option<(&[u8], &[u8])> = Some((b"/*", b"*/"));

impl Syntax {
    pub(crate) fn for_language(language: Language) -> Syntax {
        match language {
            Language::C => Syntax {
                line: SLASHES,
                block: SLASH_STAR,
                double_quote: true,
                single_quote: true,
                ..NONE
            },
            Language::Cpp => Syntax {
                line: SLASHES,
                block: SLASH_STAR,
                double_quote: true,
                single_quote: true,
                cpp_raw: true,
                ..NONE
            },
            Language::CSharp => Syntax {
                line: SLASHES,
                block: SLASH_STAR,
                double_quote: true,
                single_quote: true,
                csharp_verbatim: true,
                ..NONE
            },
            Language::Css => Syntax {
                block: SLASH_STAR,
                double_quote: true,
                single_quote: true,
                ..NONE
            },
            Language::Go => Syntax {
                line: SLASHES,
                block: SLASH_STAR,
                double_quote: true,
                single_quote: true,
                go_raw: true,
                ..NONE
            },
            Language::Html => Syntax {
                block: Some((b"<!--", b"-->")),
                ..NONE
            },
            Language::Java => Syntax {
                line: SLASHES,
                block: SLASH_STAR,
                double_quote: true,
                single_quote: true,
                triple_double: true,
                ..NONE
            },
            Language::JavaScript | Language::TypeScript => Syntax {
                line: SLASHES,
                block: SLASH_STAR,
                double_quote: true,
                single_quote: true,
                js: true,
                ..NONE
            },
            Language::Python => Syntax {
                line: Some(b"#"),
                double_quote: true,
                single_quote: true,
                triple_double: true,
                triple_single: true,
                python_prefix: true,
                ..NONE
            },
            Language::Rust => Syntax {
                line: SLASHES,
                block: SLASH_STAR,
                nests: true,
                double_quote: true,
                single_quote: true,
                rust: true,
                ..NONE
            },
            Language::Sql => Syntax {
                line: Some(b"--"),
                block: SLASH_STAR,
                double_quote: true,
                single_quote: true,
                sql: true,
                ..NONE
            },
            Language::Swift => Syntax {
                line: SLASHES,
                block: SLASH_STAR,
                nests: true,
                double_quote: true,
                triple_double: true,
                swift_raw: true,
                ..NONE
            },
        }
    }
}