| #!/usr/bin/env python | |
| # -*- coding: ascii -*- | |
| r""" | |
| ===================== | |
| Javascript Minifier | |
| ===================== | |
| rJSmin is a javascript minifier written in python. | |
| The minifier is based on the semantics of `jsmin.c by Douglas Crockford`_\\. | |
| :Copyright: | |
| Copyright 2011 - 2015 | |
| Andr\xe9 Malo or his licensors, as applicable | |
| :License: | |
| Licensed under the Apache License, Version 2.0 (the "License"); | |
| you may not use this file except in compliance with the License. | |
| You may obtain a copy of the License at | |
| http://www.apache.org/licenses/LICENSE-2.0 | |
| Unless required by applicable law or agreed to in writing, software | |
| distributed under the License is distributed on an "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| See the License for the specific language governing permissions and | |
| limitations under the License. | |
| The module is a re-implementation aiming for speed, so it can be used at | |
| runtime (rather than during a preprocessing step). Usually it produces the | |
| same results as the original ``jsmin.c``. It differs in the following ways: | |
| - there is no error detection: unterminated string, regex and comment | |
| literals are treated as regular javascript code and minified as such. | |
| - Control characters inside string and regex literals are left untouched; they | |
| are not converted to spaces (nor to \\n) | |
| - Newline characters are not allowed inside string and regex literals, except | |
| for line continuations in string literals (ECMA-5). | |
| - "return /regex/" is recognized correctly. | |
| - Line terminators after regex literals are handled more sensibly | |
| - "+ +" and "- -" sequences are not collapsed to '++' or '--' | |
| - Newlines before ! operators are removed more sensibly | |
| - Comments starting with an exclamation mark (``!``) can be kept optionally | |
| - rJSmin does not handle streams, but only complete strings. (However, the | |
| module provides a "streamy" interface). | |
| Since most parts of the logic are handled by the regex engine it's way faster | |
| than the original python port of ``jsmin.c`` by Baruch Even. The speed factor | |
| varies between about 6 and 55 depending on input and python version (it gets | |
| faster the more compressed the input already is). Compared to the | |
| speed-refactored python port by Dave St.Germain the performance gain is less | |
| dramatic but still between 3 and 50 (for huge inputs). See the docs/BENCHMARKS | |
| file for details. | |
| rjsmin.c is a reimplementation of rjsmin.py in C and speeds it up even more. | |
| Both python 2 and python 3 are supported. | |
| .. _jsmin.c by Douglas Crockford: | |
| http://www.crockford.com/javascript/jsmin.c | |
| """ | |
| if __doc__: | |
| # pylint: disable = redefined-builtin | |
| __doc__ = __doc__.encode('ascii').decode('unicode_escape') | |
| __author__ = r"Andr\xe9 Malo".encode('ascii').decode('unicode_escape') | |
| __docformat__ = "restructuredtext en" | |
| __license__ = "Apache License, Version 2.0" | |
| __version__ = '1.0.12' | |
| __all__ = ['jsmin'] | |
| import re as _re | |
| def _make_jsmin(python_only=False): | |
| """ | |
| Generate JS minifier based on `jsmin.c by Douglas Crockford`_ | |
| .. _jsmin.c by Douglas Crockford: | |
| http://www.crockford.com/javascript/jsmin.c | |
| :Parameters: | |
| `python_only` : ``bool`` | |
| Use only the python variant. If true, the c extension is not even | |
| tried to be loaded. | |
| :Return: Minifier | |
| :Rtype: ``callable`` | |
| """ | |
| # pylint: disable = unused-variable | |
| # pylint: disable = too-many-locals | |
| if not python_only: | |
| try: | |
| import _rjsmin | |
| except ImportError: | |
| pass | |
| else: | |
| return _rjsmin.jsmin | |
| try: | |
| xrange | |
| except NameError: | |
| xrange = range # pylint: disable = redefined-builtin | |
| space_chars = r'[\000-\011\013\014\016-\040]' | |
| line_comment = r'(?://[^\r\n]*)' | |
| space_comment = r'(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)' | |
| space_comment_nobang = r'(?:/\*(?!!)[^*]*\*+(?:[^/*][^*]*\*+)*/)' | |
| bang_comment = r'(?:/\*![^*]*\*+(?:[^/*][^*]*\*+)*/)' | |
| string1 = \ | |
| r'(?:\047[^\047\\\r\n]*(?:\\(?:[^\r\n]|\r?\n|\r)[^\047\\\r\n]*)*\047)' | |
| string2 = r'(?:"[^"\\\r\n]*(?:\\(?:[^\r\n]|\r?\n|\r)[^"\\\r\n]*)*")' | |
| string3 = r'(?:`(?:[^`\\]|\\.)*`)' | |
| strings = r'(?:%s|%s|%s)' % (string1, string2, string3) | |
| charclass = r'(?:\[[^\\\]\r\n]*(?:\\[^\r\n][^\\\]\r\n]*)*\])' | |
| nospecial = r'[^/\\\[\r\n]' | |
| regex = r'(?:/(?![\r\n/*])%s*(?:(?:\\[^\r\n]|%s)%s*)*/)' % ( | |
| nospecial, charclass, nospecial | |
| ) | |
| space = r'(?:%s|%s)' % (space_chars, space_comment) | |
| newline = r'(?:%s?[\r\n])' % line_comment | |
| def fix_charclass(result): | |
| """ Fixup string of chars to fit into a regex char class """ | |
| pos = result.find('-') | |
| if pos >= 0: | |
| result = r'%s%s-' % (result[:pos], result[pos + 1:]) | |
| def sequentize(string): | |
| """ | |
| Notate consecutive characters as sequence | |
| (1-4 instead of 1234) | |
| """ | |
| first, last, result = None, None, [] | |
| for char in map(ord, string): | |
| if last is None: | |
| first = last = char | |
| elif last + 1 == char: | |
| last = char | |
| else: | |
| result.append((first, last)) | |
| first = last = char | |
| if last is not None: | |
| result.append((first, last)) | |
| return ''.join(['%s%s%s' % ( | |
| chr(first), | |
| last > first + 1 and '-' or '', | |
| last != first and chr(last) or '' | |
| ) for first, last in result]) # noqa | |
| return _re.sub( | |
| r'([\000-\040\047])', # \047 for better portability | |
| lambda m: '\\%03o' % ord(m.group(1)), ( | |
| sequentize(result) | |
| .replace('\\', '\\\\') | |
| .replace('[', '\\[') | |
| .replace(']', '\\]') | |
| ) | |
| ) | |
| def id_literal_(what): | |
| """ Make id_literal like char class """ | |
| match = _re.compile(what).match | |
| result = ''.join([ | |
| chr(c) for c in xrange(127) if not match(chr(c)) | |
| ]) | |
| return '[^%s]' % fix_charclass(result) | |
| def not_id_literal_(keep): | |
| """ Make negated id_literal like char class """ | |
| match = _re.compile(id_literal_(keep)).match | |
| result = ''.join([ | |
| chr(c) for c in xrange(127) if not match(chr(c)) | |
| ]) | |
| return r'[%s]' % fix_charclass(result) | |
| not_id_literal = not_id_literal_(r'[a-zA-Z0-9_$]') | |
| preregex1 = r'[(,=:\[!&|?{};\r\n]' | |
| preregex2 = r'%(not_id_literal)sreturn' % locals() | |
| id_literal = id_literal_(r'[a-zA-Z0-9_$]') | |
| id_literal_open = id_literal_(r'[a-zA-Z0-9_${\[(!+-]') | |
| id_literal_close = id_literal_(r'[a-zA-Z0-9_$}\])"\047+-]') | |
| post_regex_off = id_literal_(r'[^\000-\040}\])?:|,;.&=+-]') | |
| dull = r'[^\047"`/\000-\040]' | |
| space_sub_simple = _re.compile(( | |
| # noqa pylint: disable = bad-continuation | |
| r'(%(dull)s+)' # 0 | |
| r'|(%(strings)s%(dull)s*)' # 1 | |
| r'|(?<=%(preregex1)s)' | |
| r'%(space)s*(?:%(newline)s%(space)s*)*' | |
| r'(%(regex)s)' # 2 | |
| r'(%(space)s*(?:%(newline)s%(space)s*)+' # 3 | |
| r'(?=%(post_regex_off)s))?' | |
| r'|(?<=%(preregex2)s)' | |
| r'%(space)s*(?:(%(newline)s)%(space)s*)*' # 4 | |
| r'(%(regex)s)' # 5 | |
| r'(%(space)s*(?:%(newline)s%(space)s*)+' # 6 | |
| r'(?=%(post_regex_off)s))?' | |
| r'|(?<=%(id_literal_close)s)' | |
| r'%(space)s*(?:(%(newline)s)%(space)s*)+' # 7 | |
| r'(?=%(id_literal_open)s)' | |
| r'|(?<=%(id_literal)s)(%(space)s)+(?=%(id_literal)s)' # 8 | |
| r'|(?<=\+)(%(space)s)+(?=\+)' # 9 | |
| r'|(?<=-)(%(space)s)+(?=-)' # 10 | |
| r'|%(space)s+' | |
| r'|(?:%(newline)s%(space)s*)+' | |
| ) % locals()).sub | |
| # print space_sub_simple.__self__.pattern | |
| def space_subber_simple(match): | |
| """ Substitution callback """ | |
| # pylint: disable = too-many-return-statements | |
| groups = match.groups() | |
| if groups[0]: | |
| return groups[0] | |
| elif groups[1]: | |
| return groups[1] | |
| elif groups[2]: | |
| if groups[3]: | |
| return groups[2] + '\n' | |
| return groups[2] | |
| elif groups[5]: | |
| return "%s%s%s" % ( | |
| groups[4] and '\n' or '', | |
| groups[5], | |
| groups[6] and '\n' or '', | |
| ) | |
| elif groups[7]: | |
| return '\n' | |
| elif groups[8] or groups[9] or groups[10]: | |
| return ' ' | |
| else: | |
| return '' | |
| space_sub_banged = _re.compile(( | |
| # noqa pylint: disable = bad-continuation | |
| r'(%(dull)s+)' # 0 | |
| r'|(%(strings)s%(dull)s*)' # 1 | |
| r'|(?<=%(preregex1)s)' | |
| r'(%(space)s*(?:%(newline)s%(space)s*)*)' # 2 | |
| r'(%(regex)s)' # 3 | |
| r'(%(space)s*(?:%(newline)s%(space)s*)+' # 4 | |
| r'(?=%(post_regex_off)s))?' | |
| r'|(?<=%(preregex2)s)' | |
| r'(%(space)s*(?:(%(newline)s)%(space)s*)*)' # 5, 6 | |
| r'(%(regex)s)' # 7 | |
| r'(%(space)s*(?:%(newline)s%(space)s*)+' # 8 | |
| r'(?=%(post_regex_off)s))?' | |
| r'|(?<=%(id_literal_close)s)' | |
| r'(%(space)s*(?:%(newline)s%(space)s*)+)' # 9 | |
| r'(?=%(id_literal_open)s)' | |
| r'|(?<=%(id_literal)s)(%(space)s+)(?=%(id_literal)s)' # 10 | |
| r'|(?<=\+)(%(space)s+)(?=\+)' # 11 | |
| r'|(?<=-)(%(space)s+)(?=-)' # 12 | |
| r'|(%(space)s+)' # 13 | |
| r'|((?:%(newline)s%(space)s*)+)' # 14 | |
| ) % locals()).sub | |
| # print space_sub_banged.__self__.pattern | |
| keep = _re.compile(( | |
| r'%(space_chars)s+|%(space_comment_nobang)s+|%(newline)s+' | |
| r'|(%(bang_comment)s+)' | |
| ) % locals()).sub | |
| keeper = lambda m: m.groups()[0] or '' | |
| # print keep.__self__.pattern | |
| def space_subber_banged(match): | |
| """ Substitution callback """ | |
| # pylint: disable = too-many-return-statements | |
| groups = match.groups() | |
| if groups[0]: | |
| return groups[0] | |
| elif groups[1]: | |
| return groups[1] | |
| elif groups[3]: | |
| return "%s%s%s%s" % ( | |
| keep(keeper, groups[2]), | |
| groups[3], | |
| keep(keeper, groups[4] or ''), | |
| groups[4] and '\n' or '', | |
| ) | |
| elif groups[7]: | |
| return "%s%s%s%s%s" % ( | |
| keep(keeper, groups[5]), | |
| groups[6] and '\n' or '', | |
| groups[7], | |
| keep(keeper, groups[8] or ''), | |
| groups[8] and '\n' or '', | |
| ) | |
| elif groups[9]: | |
| return keep(keeper, groups[9]) + '\n' | |
| elif groups[10] or groups[11] or groups[12]: | |
| return keep(keeper, groups[10] or groups[11] or groups[12]) or ' ' | |
| else: | |
| return keep(keeper, groups[13] or groups[14]) | |
| def jsmin(script, keep_bang_comments=False): | |
| r""" | |
| Minify javascript based on `jsmin.c by Douglas Crockford`_\. | |
| Instead of parsing the stream char by char, it uses a regular | |
| expression approach which minifies the whole script with one big | |
| substitution regex. | |
| .. _jsmin.c by Douglas Crockford: | |
| http://www.crockford.com/javascript/jsmin.c | |
| :Parameters: | |
| `script` : ``str`` | |
| Script to minify | |
| `keep_bang_comments` : ``bool`` | |
| Keep comments starting with an exclamation mark? (``/*!...*/``) | |
| :Return: Minified script | |
| :Rtype: ``str`` | |
| """ | |
| # pylint: disable = redefined-outer-name | |
| if keep_bang_comments: | |
| return space_sub_banged( | |
| space_subber_banged, '\n%s\n' % script | |
| ).strip() | |
| else: | |
| return space_sub_simple( | |
| space_subber_simple, '\n%s\n' % script | |
| ).strip() | |
| return jsmin | |
| jsmin = _make_jsmin() | |
| def jsmin_for_posers(script, keep_bang_comments=False): | |
| r""" | |
| Minify javascript based on `jsmin.c by Douglas Crockford`_\. | |
| Instead of parsing the stream char by char, it uses a regular | |
| expression approach which minifies the whole script with one big | |
| substitution regex. | |
| .. _jsmin.c by Douglas Crockford: | |
| http://www.crockford.com/javascript/jsmin.c | |
| :Warning: This function is the digest of a _make_jsmin() call. It just | |
| utilizes the resulting regexes. It's here for fun and may | |
| vanish any time. Use the `jsmin` function instead. | |
| :Parameters: | |
| `script` : ``str`` | |
| Script to minify | |
| `keep_bang_comments` : ``bool`` | |
| Keep comments starting with an exclamation mark? (``/*!...*/``) | |
| :Return: Minified script | |
| :Rtype: ``str`` | |
| """ | |
| if not keep_bang_comments: | |
| rex = ( | |
| r'([^\047"/\000-\040]+)|((?:(?:\047[^\047\\\r\n]*(?:\\(?:[^\r\n]' | |
| r'|\r?\n|\r)[^\047\\\r\n]*)*\047)|(?:"[^"\\\r\n]*(?:\\(?:[^\r\n]' | |
| r'|\r?\n|\r)[^"\\\r\n]*)*"))[^\047"/\000-\040]*)|(?<=[(,=:\[!&|?' | |
| r'{};\r\n])(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*' | |
| r'][^*]*\*+)*/))*(?:(?:(?://[^\r\n]*)?[\r\n])(?:[\000-\011\013\0' | |
| r'14\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*)*((?:/(?![\r' | |
| r'\n/*])[^/\\\[\r\n]*(?:(?:\\[^\r\n]|(?:\[[^\\\]\r\n]*(?:\\[^\r' | |
| r'\n][^\\\]\r\n]*)*\]))[^/\\\[\r\n]*)*/))((?:[\000-\011\013\014' | |
| r'\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*(?:(?:(?://[^\r' | |
| r'\n]*)?[\r\n])(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:' | |
| r'[^/*][^*]*\*+)*/))*)+(?=[^\000-\040&)+,.:;=?\]|}-]))?|(?<=[\00' | |
| r'0-#%-,./:-@\[-^`{-~-]return)(?:[\000-\011\013\014\016-\040]|(?' | |
| r':/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*(?:((?:(?://[^\r\n]*)?[\r\n]' | |
| r'))(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*' | |
| r'\*+)*/))*)*((?:/(?![\r\n/*])[^/\\\[\r\n]*(?:(?:\\[^\r\n]|(?:\[' | |
| r'[^\\\]\r\n]*(?:\\[^\r\n][^\\\]\r\n]*)*\]))[^/\\\[\r\n]*)*/))((' | |
| r'?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)' | |
| r'*/))*(?:(?:(?://[^\r\n]*)?[\r\n])(?:[\000-\011\013\014\016-\04' | |
| r'0]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*)+(?=[^\000-\040&)+,.:;' | |
| r'=?\]|}-]))?|(?<=[^\000-!#%&(*,./:-@\[\\^`{|~])(?:[\000-\011\01' | |
| r'3\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*(?:((?:(?:' | |
| r'//[^\r\n]*)?[\r\n]))(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]' | |
| r'*\*+(?:[^/*][^*]*\*+)*/))*)+(?=[^\000-\040"#%-\047)*,./:-@\\-^' | |
| r'`|-~])|(?<=[^\000-#%-,./:-@\[-^`{-~-])((?:[\000-\011\013\014\0' | |
| r'16-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)))+(?=[^\000-#%-,./' | |
| r':-@\[-^`{-~-])|(?<=\+)((?:[\000-\011\013\014\016-\040]|(?:/\*[' | |
| r'^*]*\*+(?:[^/*][^*]*\*+)*/)))+(?=\+)|(?<=-)((?:[\000-\011\013' | |
| r'\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)))+(?=-)|(?:[' | |
| r'\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)' | |
| r')+|(?:(?:(?://[^\r\n]*)?[\r\n])(?:[\000-\011\013\014\016-\040]' | |
| r'|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*)+' | |
| ) | |
| def subber(match): | |
| """ Substitution callback """ | |
| groups = match.groups() | |
| return ( | |
| groups[0] or | |
| groups[1] or | |
| (groups[3] and (groups[2] + '\n')) or | |
| groups[2] or | |
| (groups[5] and "%s%s%s" % ( | |
| groups[4] and '\n' or '', | |
| groups[5], | |
| groups[6] and '\n' or '', | |
| )) or | |
| (groups[7] and '\n') or | |
| (groups[8] and ' ') or | |
| (groups[9] and ' ') or | |
| (groups[10] and ' ') or | |
| '' | |
| ) | |
| else: | |
| rex = ( | |
| r'([^\047"/\000-\040]+)|((?:(?:\047[^\047\\\r\n]*(?:\\(?:[^\r\n]' | |
| r'|\r?\n|\r)[^\047\\\r\n]*)*\047)|(?:"[^"\\\r\n]*(?:\\(?:[^\r\n]' | |
| r'|\r?\n|\r)[^"\\\r\n]*)*"))[^\047"/\000-\040]*)|(?<=[(,=:\[!&|?' | |
| r'{};\r\n])((?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/' | |
| r'*][^*]*\*+)*/))*(?:(?:(?://[^\r\n]*)?[\r\n])(?:[\000-\011\013' | |
| r'\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*)*)((?:/(?!' | |
| r'[\r\n/*])[^/\\\[\r\n]*(?:(?:\\[^\r\n]|(?:\[[^\\\]\r\n]*(?:\\[^' | |
| r'\r\n][^\\\]\r\n]*)*\]))[^/\\\[\r\n]*)*/))((?:[\000-\011\013\01' | |
| r'4\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*(?:(?:(?://[^' | |
| r'\r\n]*)?[\r\n])(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(' | |
| r'?:[^/*][^*]*\*+)*/))*)+(?=[^\000-\040&)+,.:;=?\]|}-]))?|(?<=[' | |
| r'\000-#%-,./:-@\[-^`{-~-]return)((?:[\000-\011\013\014\016-\040' | |
| r']|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*(?:((?:(?://[^\r\n]*)?[' | |
| r'\r\n]))(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][' | |
| r'^*]*\*+)*/))*)*)((?:/(?![\r\n/*])[^/\\\[\r\n]*(?:(?:\\[^\r\n]|' | |
| r'(?:\[[^\\\]\r\n]*(?:\\[^\r\n][^\\\]\r\n]*)*\]))[^/\\\[\r\n]*)*' | |
| r'/))((?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]' | |
| r'*\*+)*/))*(?:(?:(?://[^\r\n]*)?[\r\n])(?:[\000-\011\013\014\01' | |
| r'6-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*)+(?=[^\000-\040&)' | |
| r'+,.:;=?\]|}-]))?|(?<=[^\000-!#%&(*,./:-@\[\\^`{|~])((?:[\000-' | |
| r'\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*(?:' | |
| r'(?:(?://[^\r\n]*)?[\r\n])(?:[\000-\011\013\014\016-\040]|(?:/' | |
| r'\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*)+)(?=[^\000-\040"#%-\047)*,./' | |
| r':-@\\-^`|-~])|(?<=[^\000-#%-,./:-@\[-^`{-~-])((?:[\000-\011\01' | |
| r'3\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))+)(?=[^\000' | |
| r'-#%-,./:-@\[-^`{-~-])|(?<=\+)((?:[\000-\011\013\014\016-\040]|' | |
| r'(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))+)(?=\+)|(?<=-)((?:[\000-\0' | |
| r'11\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))+)(?=-' | |
| r')|((?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*' | |
| r'\*+)*/))+)|((?:(?:(?://[^\r\n]*)?[\r\n])(?:[\000-\011\013\014' | |
| r'\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*)+)' | |
| ) | |
| keep = _re.compile(( | |
| r'[\000-\011\013\014\016-\040]+|(?:/\*(?!!)[^*]*\*+(?:[^/*][^*]*' | |
| r'\*+)*/)+|(?:(?://[^\r\n]*)?[\r\n])+|((?:/\*![^*]*\*+(?:[^/*][^' | |
| r'*]*\*+)*/)+)' | |
| ) % locals()).sub | |
| keeper = lambda m: m.groups()[0] or '' | |
| def subber(match): | |
| """ Substitution callback """ | |
| groups = match.groups() | |
| return ( | |
| groups[0] or | |
| groups[1] or | |
| (groups[3] and "%s%s%s%s" % ( | |
| keep(keeper, groups[2]), | |
| groups[3], | |
| keep(keeper, groups[4] or ''), | |
| groups[4] and '\n' or '', | |
| )) or | |
| (groups[7] and "%s%s%s%s%s" % ( | |
| keep(keeper, groups[5]), | |
| groups[6] and '\n' or '', | |
| groups[7], | |
| keep(keeper, groups[8] or ''), | |
| groups[8] and '\n' or '', | |
| )) or | |
| (groups[9] and keep(keeper, groups[9] + '\n')) or | |
| (groups[10] and keep(keeper, groups[10]) or ' ') or | |
| (groups[11] and keep(keeper, groups[11]) or ' ') or | |
| (groups[12] and keep(keeper, groups[12]) or ' ') or | |
| keep(keeper, groups[13] or groups[14]) | |
| ) | |
| return _re.sub(rex, subber, '\n%s\n' % script).strip() | |
| if __name__ == '__main__': | |
| def main(): | |
| """ Main """ | |
| import sys as _sys | |
| argv = _sys.argv[1:] | |
| keep_bang_comments = '-b' in argv or '-bp' in argv or '-pb' in argv | |
| if '-p' in argv or '-bp' in argv or '-pb' in argv: | |
| xjsmin = _make_jsmin(python_only=True) | |
| else: | |
| xjsmin = jsmin | |
| _sys.stdout.write(xjsmin( | |
| _sys.stdin.read(), keep_bang_comments=keep_bang_comments | |
| )) | |
| main() |