1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// Take a look at the license at the top of the repository in the LICENSE file.

use crate::json::{
    json_minifier::{keep_element, JsonMinifier},
    read::json_read::JsonRead,
    string::JsonMultiFilter,
};
use std::fmt;
use std::io::{self, Read};

mod read {
    mod byte_to_char;
    mod internal_buffer;
    mod internal_reader;
    pub mod json_read;
}

mod json_minifier;
mod string;

type JsonMethod = fn(&mut JsonMinifier, &char, Option<&char>) -> bool;

/// Minifies a given String by JSON minification rules
///
/// # Example
///
/// ```rust
/// use minifier::json::minify;
///
/// let json = r#"
///        {
///            "test": "test",
///            "test2": 2
///        }
///    "#.into();
/// let json_minified = minify(json);
/// assert_eq!(&json_minified.to_string(), r#"{"test":"test","test2":2}"#);
/// ```
#[inline]
pub fn minify(json: &str) -> Minified<'_> {
    Minified(JsonMultiFilter::new(json.chars(), keep_element))
}

#[derive(Debug)]
pub struct Minified<'a>(JsonMultiFilter<'a, JsonMethod>);

impl<'a> Minified<'a> {
    pub fn write<W: io::Write>(self, w: W) -> io::Result<()> {
        self.0.write(w)
    }
}

impl<'a> fmt::Display for Minified<'a> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)
    }
}

/// Minifies a given Read by JSON minification rules
///
/// # Example
///
/// ```rust
/// extern crate minifier;
/// use std::fs::File;
/// use std::io::Read;
/// use minifier::json::minify_from_read;
///
/// fn main() {
///     let mut html_minified = String::new();
///     let mut file = File::open("tests/files/test.json").expect("file not found");
///     minify_from_read(file).read_to_string(&mut html_minified);
/// }
/// ```
#[inline]
pub fn minify_from_read<R: Read>(json: R) -> JsonRead<JsonMethod, R> {
    JsonRead::new(json, keep_element)
}

#[test]
fn removal_from_read() {
    use std::fs::File;

    let input = File::open("tests/files/test.json").expect("file not found");
    let expected: String = "{\"test\":\"\\\" test2\",\"test2\":\"\",\"test3\":\" \"}".into();
    let mut actual = String::new();
    minify_from_read(input)
        .read_to_string(&mut actual)
        .expect("error at read");
    assert_eq!(actual, expected);
}

#[test]
fn removal_of_control_characters() {
    let input = "\n".into();
    let expected: String = "".into();
    let actual = minify(input);
    assert_eq!(actual.to_string(), expected);
}

#[test]
fn removal_of_whitespace_outside_of_tags() {
    let input = r#"
            {
              "test": "\" test2",
              "test2": "",
              "test3": " "
            }
        "#
    .into();
    let expected: String = "{\"test\":\"\\\" test2\",\"test2\":\"\",\"test3\":\" \"}".into();
    let actual = minify(input);
    assert_eq!(actual.to_string(), expected);
}