pub use self::parser::parse_schema;

/// The AST data structure. It aims to faithfully represent the syntax of a Prisma Schema, with
/// source span information.
pub mod ast;

/// The validation or parser errors and warnings
pub(crate) use prisma_diagnostics as diagnostics;

mod parser;

/// Transform the input string into a valid (quoted and escaped) PSL string literal.
///
/// PSL string literals have the exact same grammar as [JSON string
/// literals](https://datatracker.ietf.org/doc/html/rfc8259#section-7).
///
/// ```
/// # use schema_ast::string_literal;
/// let input = r#"oh
/// hi"#;
/// assert_eq!(r#""oh\nhi""#, &string_literal(input).to_string());
/// ```
pub fn string_literal(s: &str) -> impl std::fmt::Display + '_ {
    struct StringLiteral<'a>(&'a str);

    impl std::fmt::Display for StringLiteral<'_> {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            f.write_str("\"")?;
            for c in self.0.char_indices() {
                match c {
                    (_, '\t') => f.write_str("\\t")?,
                    (_, '\n') => f.write_str("\\n")?,
                    (_, '"') => f.write_str("\\\"")?,
                    (_, '\r') => f.write_str("\\r")?,
                    (_, '\\') => f.write_str("\\\\")?,
                    // Control characters
                    (_, c) if c.is_ascii_control() => {
                        let mut b = [0];
                        c.encode_utf8(&mut b);
                        f.write_fmt(format_args!("\\u{:04x}", b[0]))?;
                    }
                    (start, other) => f.write_str(&self.0[start..(start + other.len_utf8())])?,
                }
            }
            f.write_str("\"")
        }
    }

    StringLiteral(s)
}
