#![no_std]
#![forbid(unsafe_code)]
#![doc(html_root_url = "https://docs.rs/js-string-escape/0.1.0")]
extern crate alloc;
use alloc::string::String;
#[cfg(doctest)]
#[doc = include_str!("../README.md")]
struct ReadmeDoctests;
#[must_use]
pub fn js_string_escape(string: &str) -> String {
let mut out = String::with_capacity(string.len());
for character in string.chars() {
match character {
'"' | '\'' | '\\' => {
out.push('\\');
out.push(character);
}
'\n' => out.push_str("\\n"),
'\r' => out.push_str("\\r"),
'\u{2028}' => out.push_str("\\u2028"),
'\u{2029}' => out.push_str("\\u2029"),
_ => out.push(character),
}
}
out
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn escapes_quotes_and_backslash() {
assert_eq!(js_string_escape("a\"b"), "a\\\"b");
assert_eq!(js_string_escape("a'b"), "a\\'b");
assert_eq!(js_string_escape("a\\b"), "a\\\\b");
}
#[test]
fn escapes_line_terminators() {
assert_eq!(js_string_escape("a\nb"), "a\\nb");
assert_eq!(js_string_escape("a\rb"), "a\\rb");
assert_eq!(js_string_escape("a\u{2028}b"), "a\\u2028b");
assert_eq!(js_string_escape("a\u{2029}b"), "a\\u2029b");
}
#[test]
fn leaves_other_characters_untouched() {
assert_eq!(js_string_escape("a\tb"), "a\tb");
assert_eq!(js_string_escape("a\u{0}b"), "a\u{0}b");
assert_eq!(js_string_escape("x`y"), "x`y");
assert_eq!(js_string_escape("café 😀"), "café 😀");
assert_eq!(js_string_escape(""), "");
assert_eq!(js_string_escape("plain"), "plain");
}
}