OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # -*- coding: ascii -*- | |
3 # | 2 # |
4 # Copyright 2011 - 2013 | 3 # Copyright 2011 - 2013 |
5 # Andr\xe9 Malo or his licensors, as applicable | 4 # Andr\xe9 Malo or his licensors, as applicable |
6 # | 5 # |
7 # Licensed under the Apache License, Version 2.0 (the "License"); | 6 # Licensed under the Apache License, Version 2.0 (the "License"); |
8 # you may not use this file except in compliance with the License. | 7 # you may not use this file except in compliance with the License. |
9 # You may obtain a copy of the License at | 8 # You may obtain a copy of the License at |
10 # | 9 # |
11 # http://www.apache.org/licenses/LICENSE-2.0 | 10 # http://www.apache.org/licenses/LICENSE-2.0 |
12 # | 11 # |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
84 if not python_only: | 83 if not python_only: |
85 try: | 84 try: |
86 import _rjsmin | 85 import _rjsmin |
87 except ImportError: | 86 except ImportError: |
88 pass | 87 pass |
89 else: | 88 else: |
90 return _rjsmin.jsmin | 89 return _rjsmin.jsmin |
91 try: | 90 try: |
92 xrange | 91 xrange |
93 except NameError: | 92 except NameError: |
94 xrange = range # pylint: disable = W0622 | 93 xrange = range # pylint: disable = W0622 |
Daniel Bratell
2014/04/25 09:49:39
The changes I've done in this file is just to get
| |
95 | 94 |
96 space_chars = r'[\000-\011\013\014\016-\040]' | 95 space_chars = r'[\000-\011\013\014\016-\040]' |
97 | 96 |
98 line_comment = r'(?://[^\r\n]*)' | 97 line_comment = r'(?://[^\r\n]*)' |
99 space_comment = r'(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)' | 98 space_comment = r'(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)' |
100 string1 = \ | 99 string1 = \ |
101 r'(?:\047[^\047\\\r\n]*(?:\\(?:[^\r\n]|\r?\n|\r)[^\047\\\r\n]*)*\047)' | 100 r'(?:\047[^\047\\\r\n]*(?:\\(?:[^\r\n]|\r?\n|\r)[^\047\\\r\n]*)*\047)' |
102 string2 = r'(?:"[^"\\\r\n]*(?:\\(?:[^\r\n]|\r?\n|\r)[^"\\\r\n]*)*")' | 101 string2 = r'(?:"[^"\\\r\n]*(?:\\(?:[^\r\n]|\r?\n|\r)[^"\\\r\n]*)*")' |
103 strings = r'(?:%s|%s)' % (string1, string2) | 102 strings = r'(?:%s|%s)' % (string1, string2) |
104 | 103 |
105 charclass = r'(?:\[[^\\\]\r\n]*(?:\\[^\r\n][^\\\]\r\n]*)*\])' | 104 charclass = r'(?:\[[^\\\]\r\n]*(?:\\[^\r\n][^\\\]\r\n]*)*\])' |
106 nospecial = r'[^/\\\[\r\n]' | 105 nospecial = r'[^/\\\[\r\n]' |
107 regex = r'(?:/(?![\r\n/*])%s*(?:(?:\\[^\r\n]|%s)%s*)*/)' % ( | 106 regex = r'(?:/(?![\r\n/*])%s*(?:(?:\\[^\r\n]|%s)%s*)*/)' % ( |
108 nospecial, charclass, nospecial | 107 nospecial, charclass, nospecial) |
109 ) | |
110 space = r'(?:%s|%s)' % (space_chars, space_comment) | 108 space = r'(?:%s|%s)' % (space_chars, space_comment) |
111 newline = r'(?:%s?[\r\n])' % line_comment | 109 newline = r'(?:%s?[\r\n])' % line_comment |
112 | 110 |
113 def fix_charclass(result): | 111 def fix_charclass(result): |
114 """ Fixup string of chars to fit into a regex char class """ | 112 """ Fixup string of chars to fit into a regex char class """ |
115 pos = result.find('-') | 113 pos = result.find('-') |
116 if pos >= 0: | 114 if pos >= 0: |
117 result = r'%s%s-' % (result[:pos], result[pos + 1:]) | 115 result = r'%s%s-' % (result[:pos], result[pos + 1:]) |
118 | 116 |
119 def sequentize(string): | 117 def sequentize(string): |
120 """ | 118 """ |
121 Notate consecutive characters as sequence | 119 Notate consecutive characters as sequence |
122 | 120 |
123 (1-4 instead of 1234) | 121 (1-4 instead of 1234) |
124 """ | 122 """ |
125 first, last, result = None, None, [] | 123 first, last, result = None, None, [] |
126 for char in map(ord, string): | 124 for char in map(ord, string): |
127 if last is None: | 125 if last is None: |
128 first = last = char | 126 first = last = char |
129 elif last + 1 == char: | 127 elif last + 1 == char: |
130 last = char | 128 last = char |
131 else: | 129 else: |
132 result.append((first, last)) | 130 result.append((first, last)) |
133 first = last = char | 131 first = last = char |
134 if last is not None: | 132 if last is not None: |
135 result.append((first, last)) | 133 result.append((first, last)) |
136 return ''.join(['%s%s%s' % ( | 134 return ''.join(['%s%s%s' % ( |
137 chr(first), | 135 chr(first), |
138 last > first + 1 and '-' or '', | 136 last > first + 1 and '-' or '', |
139 last != first and chr(last) or '' | 137 last != first and chr(last) or '') for first, last in result]) |
140 ) for first, last in result]) | |
141 | 138 |
142 return _re.sub(r'([\000-\040\047])', # for better portability | 139 return _re.sub(r'([\000-\040\047])', # for better portability |
143 lambda m: '\\%03o' % ord(m.group(1)), (sequentize(result) | 140 lambda m: '\\%03o' % ord(m.group(1)), (sequentize(result) |
144 .replace('\\', '\\\\') | 141 .replace('\\', '\\\\') |
145 .replace('[', '\\[') | 142 .replace('[', '\\[') |
146 .replace(']', '\\]') | 143 .replace(']', '\\]'))) |
147 ) | |
148 ) | |
149 | 144 |
150 def id_literal_(what): | 145 def id_literal_(what): |
151 """ Make id_literal like char class """ | 146 """ Make id_literal like char class """ |
152 match = _re.compile(what).match | 147 match = _re.compile(what).match |
153 result = ''.join([ | 148 result = ''.join([chr(c) for c in xrange(127) if not match(chr(c))]) |
154 chr(c) for c in xrange(127) if not match(chr(c)) | |
155 ]) | |
156 return '[^%s]' % fix_charclass(result) | 149 return '[^%s]' % fix_charclass(result) |
157 | 150 |
158 def not_id_literal_(keep): | 151 def not_id_literal_(keep): |
159 """ Make negated id_literal like char class """ | 152 """ Make negated id_literal like char class """ |
160 match = _re.compile(id_literal_(keep)).match | 153 match = _re.compile(id_literal_(keep)).match |
161 result = ''.join([ | 154 result = ''.join([chr(c) for c in xrange(127) if not match(chr(c))]) |
162 chr(c) for c in xrange(127) if not match(chr(c)) | |
163 ]) | |
164 return r'[%s]' % fix_charclass(result) | 155 return r'[%s]' % fix_charclass(result) |
165 | 156 |
166 not_id_literal = not_id_literal_(r'[a-zA-Z0-9_$]') | 157 not_id_literal = not_id_literal_(r'[a-zA-Z0-9_$]') |
167 preregex1 = r'[(,=:\[!&|?{};\r\n]' | 158 preregex1 = r'[(,=:\[!&|?{};\r\n]' |
168 preregex2 = r'%(not_id_literal)sreturn' % locals() | 159 preregex2 = r'%(not_id_literal)sreturn' % locals() |
169 | 160 |
170 id_literal = id_literal_(r'[a-zA-Z0-9_$]') | 161 id_literal = id_literal_(r'[a-zA-Z0-9_$]') |
171 id_literal_open = id_literal_(r'[a-zA-Z0-9_${\[(!+-]') | 162 id_literal_open = id_literal_(r'[a-zA-Z0-9_${\[(!+-]') |
172 id_literal_close = id_literal_(r'[a-zA-Z0-9_$}\])"\047+-]') | 163 id_literal_close = id_literal_(r'[a-zA-Z0-9_$}\])"\047+-]') |
173 | 164 |
174 dull = r'[^\047"/\000-\040]' | 165 dull = r'[^\047"/\000-\040]' |
175 | 166 |
176 space_sub = _re.compile(( | 167 space_sub = _re.compile(( |
177 r'(%(dull)s+)' | 168 r'(%(dull)s+)' |
178 r'|(%(strings)s%(dull)s*)' | 169 r'|(%(strings)s%(dull)s*)' |
179 r'|(?<=%(preregex1)s)' | 170 r'|(?<=%(preregex1)s)' |
180 r'%(space)s*(?:%(newline)s%(space)s*)*' | 171 r'%(space)s*(?:%(newline)s%(space)s*)*' |
181 r'(%(regex)s%(dull)s*)' | 172 r'(%(regex)s%(dull)s*)' |
182 r'|(?<=%(preregex2)s)' | 173 r'|(?<=%(preregex2)s)' |
183 r'%(space)s*(?:%(newline)s%(space)s)*' | 174 r'%(space)s*(?:%(newline)s%(space)s)*' |
184 r'(%(regex)s%(dull)s*)' | 175 r'(%(regex)s%(dull)s*)' |
185 r'|(?<=%(id_literal_close)s)' | 176 r'|(?<=%(id_literal_close)s)' |
186 r'%(space)s*(?:(%(newline)s)%(space)s*)+' | 177 r'%(space)s*(?:(%(newline)s)%(space)s*)+' |
187 r'(?=%(id_literal_open)s)' | 178 r'(?=%(id_literal_open)s)' |
188 r'|(?<=%(id_literal)s)(%(space)s)+(?=%(id_literal)s)' | 179 r'|(?<=%(id_literal)s)(%(space)s)+(?=%(id_literal)s)' |
189 r'|(?<=\+)(%(space)s)+(?=\+)' | 180 r'|(?<=\+)(%(space)s)+(?=\+)' |
190 r'|(?<=-)(%(space)s)+(?=-)' | 181 r'|(?<=-)(%(space)s)+(?=-)' |
191 r'|%(space)s+' | 182 r'|%(space)s+' |
192 r'|(?:%(newline)s%(space)s*)+' | 183 r'|(?:%(newline)s%(space)s*)+') % locals()).sub |
193 ) % locals()).sub | |
194 #print space_sub.__self__.pattern | 184 #print space_sub.__self__.pattern |
195 | 185 |
196 def space_subber(match): | 186 def space_subber(match): |
197 """ Substitution callback """ | 187 """ Substitution callback """ |
198 # pylint: disable = C0321, R0911 | 188 # pylint: disable = C0321, R0911 |
199 groups = match.groups() | 189 groups = match.groups() |
200 if groups[0]: return groups[0] | 190 if groups[0]: |
201 elif groups[1]: return groups[1] | 191 return groups[0] |
202 elif groups[2]: return groups[2] | 192 elif groups[1]: |
203 elif groups[3]: return groups[3] | 193 return groups[1] |
204 elif groups[4]: return '\n' | 194 elif groups[2]: |
205 elif groups[5] or groups[6] or groups[7]: return ' ' | 195 return groups[2] |
206 else: return '' | 196 elif groups[3]: |
197 return groups[3] | |
198 elif groups[4]: | |
199 return '\n' | |
200 elif groups[5] or groups[6] or groups[7]: | |
201 return ' ' | |
202 else: | |
203 return '' | |
207 | 204 |
208 def jsmin(script): # pylint: disable = W0621 | 205 def jsmin(script): # pylint: disable = W0621 |
209 r""" | 206 r""" |
210 Minify javascript based on `jsmin.c by Douglas Crockford`_\. | 207 Minify javascript based on `jsmin.c by Douglas Crockford`_\. |
211 | 208 |
212 Instead of parsing the stream char by char, it uses a regular | 209 Instead of parsing the stream char by char, it uses a regular |
213 expression approach which minifies the whole script with one big | 210 expression approach which minifies the whole script with one big |
214 substitution regex. | 211 substitution regex. |
215 | 212 |
216 .. _jsmin.c by Douglas Crockford: | 213 .. _jsmin.c by Douglas Crockford: |
217 http://www.crockford.com/javascript/jsmin.c | 214 http://www.crockford.com/javascript/jsmin.c |
218 | 215 |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
257 groups = match.groups() | 254 groups = match.groups() |
258 return ( | 255 return ( |
259 groups[0] or | 256 groups[0] or |
260 groups[1] or | 257 groups[1] or |
261 groups[2] or | 258 groups[2] or |
262 groups[3] or | 259 groups[3] or |
263 (groups[4] and '\n') or | 260 (groups[4] and '\n') or |
264 (groups[5] and ' ') or | 261 (groups[5] and ' ') or |
265 (groups[6] and ' ') or | 262 (groups[6] and ' ') or |
266 (groups[7] and ' ') or | 263 (groups[7] and ' ') or |
267 '' | 264 '') |
268 ) | |
269 | 265 |
270 return _re.sub( | 266 return _re.sub( |
271 r'([^\047"/\000-\040]+)|((?:(?:\047[^\047\\\r\n]*(?:\\(?:[^\r\n]|\r?' | 267 r'([^\047"/\000-\040]+)|((?:(?:\047[^\047\\\r\n]*(?:\\(?:[^\r\n]|\r?' |
272 r'\n|\r)[^\047\\\r\n]*)*\047)|(?:"[^"\\\r\n]*(?:\\(?:[^\r\n]|\r?\n|' | 268 r'\n|\r)[^\047\\\r\n]*)*\047)|(?:"[^"\\\r\n]*(?:\\(?:[^\r\n]|\r?\n|' |
273 r'\r)[^"\\\r\n]*)*"))[^\047"/\000-\040]*)|(?<=[(,=:\[!&|?{};\r\n])(?' | 269 r'\r)[^"\\\r\n]*)*"))[^\047"/\000-\040]*)|(?<=[(,=:\[!&|?{};\r\n])(?' |
274 r':[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*' | 270 r':[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*' |
275 r'(?:(?:(?://[^\r\n]*)?[\r\n])(?:[\000-\011\013\014\016-\040]|(?:/\*' | 271 r'(?:(?:(?://[^\r\n]*)?[\r\n])(?:[\000-\011\013\014\016-\040]|(?:/\*' |
276 r'[^*]*\*+(?:[^/*][^*]*\*+)*/))*)*((?:/(?![\r\n/*])[^/\\\[\r\n]*(?:(' | 272 r'[^*]*\*+(?:[^/*][^*]*\*+)*/))*)*((?:/(?![\r\n/*])[^/\\\[\r\n]*(?:(' |
277 r'?:\\[^\r\n]|(?:\[[^\\\]\r\n]*(?:\\[^\r\n][^\\\]\r\n]*)*\]))[^/\\\[' | 273 r'?:\\[^\r\n]|(?:\[[^\\\]\r\n]*(?:\\[^\r\n][^\\\]\r\n]*)*\]))[^/\\\[' |
278 r'\r\n]*)*/)[^\047"/\000-\040]*)|(?<=[\000-#%-,./:-@\[-^`{-~-]return' | 274 r'\r\n]*)*/)[^\047"/\000-\040]*)|(?<=[\000-#%-,./:-@\[-^`{-~-]return' |
279 r')(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/' | 275 r')(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/' |
280 r'))*(?:(?:(?://[^\r\n]*)?[\r\n])(?:[\000-\011\013\014\016-\040]|(?:' | 276 r'))*(?:(?:(?://[^\r\n]*)?[\r\n])(?:[\000-\011\013\014\016-\040]|(?:' |
281 r'/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)))*((?:/(?![\r\n/*])[^/\\\[\r\n]*(?' | 277 r'/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)))*((?:/(?![\r\n/*])[^/\\\[\r\n]*(?' |
282 r':(?:\\[^\r\n]|(?:\[[^\\\]\r\n]*(?:\\[^\r\n][^\\\]\r\n]*)*\]))[^/' | 278 r':(?:\\[^\r\n]|(?:\[[^\\\]\r\n]*(?:\\[^\r\n][^\\\]\r\n]*)*\]))[^/' |
283 r'\\\[\r\n]*)*/)[^\047"/\000-\040]*)|(?<=[^\000-!#%&(*,./:-@\[\\^`{|' | 279 r'\\\[\r\n]*)*/)[^\047"/\000-\040]*)|(?<=[^\000-!#%&(*,./:-@\[\\^`{|' |
284 r'~])(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)' | 280 r'~])(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)' |
285 r'*/))*(?:((?:(?://[^\r\n]*)?[\r\n]))(?:[\000-\011\013\014\016-\040]' | 281 r'*/))*(?:((?:(?://[^\r\n]*)?[\r\n]))(?:[\000-\011\013\014\016-\040]' |
286 r'|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*)+(?=[^\000-\040"#%-\047)*,./' | 282 r'|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*)+(?=[^\000-\040"#%-\047)*,./' |
287 r':-@\\-^`|-~])|(?<=[^\000-#%-,./:-@\[-^`{-~-])((?:[\000-\011\013\01' | 283 r':-@\\-^`|-~])|(?<=[^\000-#%-,./:-@\[-^`{-~-])((?:[\000-\011\013\01' |
288 r'4\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)))+(?=[^\000-#%-,./:' | 284 r'4\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)))+(?=[^\000-#%-,./:' |
289 r'-@\[-^`{-~-])|(?<=\+)((?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*' | 285 r'-@\[-^`{-~-])|(?<=\+)((?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*' |
290 r'\*+(?:[^/*][^*]*\*+)*/)))+(?=\+)|(?<=-)((?:[\000-\011\013\014\016-' | 286 r'\*+(?:[^/*][^*]*\*+)*/)))+(?=\+)|(?<=-)((?:[\000-\011\013\014\016-' |
291 r'\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)))+(?=-)|(?:[\000-\011\013' | 287 r'\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)))+(?=-)|(?:[\000-\011\013' |
292 r'\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))+|(?:(?:(?://[^' | 288 r'\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))+|(?:(?:(?://[^' |
293 r'\r\n]*)?[\r\n])(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^' | 289 r'\r\n]*)?[\r\n])(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^' |
294 r'/*][^*]*\*+)*/))*)+', subber, '\n%s\n' % script | 290 r'/*][^*]*\*+)*/))*)+', subber, '\n%s\n' % script).strip() |
295 ).strip() | |
296 | 291 |
297 | 292 |
298 if __name__ == '__main__': | 293 if __name__ == '__main__': |
299 import sys as _sys | 294 import sys as _sys |
300 _sys.stdout.write(jsmin(_sys.stdin.read())) | 295 _sys.stdout.write(jsmin(_sys.stdin.read())) |
OLD | NEW |