vize_l0 0.585.0

L0 - the Davinci foundation level: ids, side tables, keys, dumps, diagnostics, passes and facts
Documentation
//! JavaScript string literals shared by compiler-owned producers.

use crate::String;

/// Append one double-quoted JavaScript string literal.
pub fn push_js_string_literal(output: &mut String, value: &str) {
    output.push('"');

    let mut segment_start = 0usize;
    for (index, char) in value.char_indices() {
        let escaped = match char {
            '"' => Some("\\\""),
            '\\' => Some("\\\\"),
            '\n' => Some("\\n"),
            '\r' => Some("\\r"),
            '\t' => Some("\\t"),
            '\u{08}' => Some("\\b"),
            '\u{0c}' => Some("\\f"),
            '\u{00}'..='\u{1f}' => {
                output.push_str(value.get(segment_start..index).unwrap_or_default());
                push_control_escape(output, char as u8);
                segment_start = index + char.len_utf8();
                None
            }
            _ => None,
        };

        if let Some(escaped) = escaped {
            output.push_str(value.get(segment_start..index).unwrap_or_default());
            output.push_str(escaped);
            segment_start = index + char.len_utf8();
        }
    }

    output.push_str(value.get(segment_start..).unwrap_or_default());
    output.push('"');
}

fn push_control_escape(output: &mut String, byte: u8) {
    output.push_str("\\u00");
    for nibble in [byte >> 4, byte & 0x0f] {
        output.push(char::from_digit(u32::from(nibble), 16).unwrap_or('0'));
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn escapes_js_string_literal_controls() {
        let mut output = String::default();
        push_js_string_literal(&mut output, "a\"b\\c\n\u{01}");
        assert_eq!(output.as_str(), r#""a\"b\\c\n\u0001""#);
    }
}