Skip to content
This repository
Newer
Older
100644 127 lines (118 sloc) 4.536 kb
fccc6851 »
2011-06-21 Initial open-source release
1 (*-
2 * Copyright (c) 2007 Eugene Ossintsev
3 * Copyright (c) 2002 Douglas Crockford
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 *)
23
24 exception Failure' = Failure
25 open Stream
26
27 let is_unsquashable a b =
28 match a, b with
29 | '+', '+' -> true
30 | '-', '-' -> true
31 | _ -> false
32
33 let is_alphanum = function
34 | 'a'..'z' | 'A'..'Z' | '0'..'9' | '_' | '$' | '\\' -> true
35 | c when ((Char.code c) > 126) -> true
36 | _ -> false
37
38 let is_pre_lf = function
39 | c when is_alphanum c -> true
40 | '}' | ']' | ')' | '+' | '-' | '\"' | '\'' | '.' -> true
41 | _ -> false
42
43 let is_post_lf = function
44 | c when is_alphanum c -> true
45 | '{' | '[' | '(' | '+' | '-' -> true
46 | _ -> false
47
48 let is_space = function
49 | '\r' | '\n' -> false
50 | c when ((Char.code c) <= (Char.code ' ')) -> true
51 | _ -> false
52
53 let is_pre_regexp = function
54 | '(' | ',' | '='| ':' | '['| '!'| '&' | '|' | '?' | '{' | '}' | ';' | '\n' -> true
55 | _ -> false
56
57 let minify str =
58 let s = of_string str in
59 let buff = Buffer.create (String.length str) in
60 let prev_ch = ref '\000' in
61 let print_ch c =
62 if not (is_space c) then prev_ch := c;
63 Buffer.add_char buff c
64 in
65 let rec next_ch () =
66 match peek s with
67 | Some '/' -> junk s; maybe_comment_or_regexp ()
68 | Some ('\'' as c) | Some ('\"' as c) -> junk s; print_ch c; quote c
69 | Some '\r' | Some '\n' -> junk s; squeeze_linefeeds ()
70 | Some c when is_space c -> junk s; squeeze_spaces ()
71 | Some c -> junk s; print_ch c; next_ch ()
72 | None -> ()
73 and squeeze_spaces () =
74 match peek s with
75 | Some c when is_space c -> junk s; squeeze_spaces ()
76 | Some c ->
77 if (is_unsquashable !prev_ch c) || ((is_alphanum !prev_ch) && (is_alphanum c))
78 then print_ch ' ';
79 next_ch ()
80 | None -> ()
81 and squeeze_linefeeds () =
82 match peek s with
83 | Some c when c = '\r' || c = '\n' || (is_space c) -> junk s; squeeze_linefeeds ()
84 | Some c -> if (is_pre_lf !prev_ch) && (is_post_lf c) then print_ch '\n'; next_ch ()
85 | None -> ()
86 and maybe_comment_or_regexp () =
87 match peek s with
88 | Some '/' -> junk s; line_comment ()
89 | Some '*' -> junk s; block_comment ()
90 | Some _ when is_pre_regexp !prev_ch -> print_ch '/'; quote '/'
91 | _ -> print_ch '/'; next_ch ()
92 and line_comment () =
93 match peek s with
94 | Some '\r' | Some '\n' -> junk s; squeeze_linefeeds ()
95 | Some _ -> junk s; line_comment ()
96 | None -> ()
97 and block_comment () =
98 match peek s with
99 | Some '*' -> junk s; maybe_block_comment_end ()
100 | Some _ -> junk s; block_comment ()
101 | None -> failwith "Unterminated comment"
102 and maybe_block_comment_end () =
103 match peek s with
104 | Some '/' -> junk s; squeeze_spaces ()
105 | Some '*' -> junk s; maybe_block_comment_end ()
106 | _ -> junk s; block_comment ()
107 and quote c =
108 match peek s with
109 | Some '\\' ->
110 junk s; print_ch '\\';
111 begin match peek s with
112 | Some c2 -> junk s; print_ch c2; quote c
113 | None -> quote c
114 end
115 | Some c2 when c2 = c -> junk s; print_ch c; next_ch ()
116 | Some '\r' | Some '\n' | None ->
117 let str = Buffer.contents buff in
118 let i = max 0 ((String.length str)-10) in
119 Printf.printf "Minify error: %s\n" (String.sub str i (min (i+100) (String.length str)));
120 failwith ("Unterminated " ^ (if c = '/' then "regular expression" else "string"))
121 | Some c2 -> junk s; print_ch c2; quote c
122 in
123 try
124 next_ch ();
125 Buffer.contents buff
126 with _ -> str
Something went wrong with that request. Please try again.