python/jsmin/jsmin/__init__.py

Fri, 16 Jan 2015 04:50:19 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 04:50:19 +0100
branch
TOR_BUG_9701
changeset 13
44a2da4a2ab2
permissions
-rw-r--r--

Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32

michael@0 1 # This code is original from jsmin by Douglas Crockford, it was translated to
michael@0 2 # Python by Baruch Even. It was rewritten by Dave St.Germain for speed.
michael@0 3 #
michael@0 4 # The MIT License (MIT)
michael@0 5 #
michael@0 6 # Copyright (c) 2013 Dave St.Germain
michael@0 7 #
michael@0 8 # Permission is hereby granted, free of charge, to any person obtaining a copy
michael@0 9 # of this software and associated documentation files (the "Software"), to deal
michael@0 10 # in the Software without restriction, including without limitation the rights
michael@0 11 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
michael@0 12 # copies of the Software, and to permit persons to whom the Software is
michael@0 13 # furnished to do so, subject to the following conditions:
michael@0 14 #
michael@0 15 # The above copyright notice and this permission notice shall be included in
michael@0 16 # all copies or substantial portions of the Software.
michael@0 17 #
michael@0 18 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
michael@0 19 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
michael@0 20 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
michael@0 21 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
michael@0 22 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
michael@0 23 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
michael@0 24 # THE SOFTWARE.
michael@0 25
michael@0 26
michael@0 27 import sys
michael@0 28 is_3 = sys.version_info >= (3, 0)
michael@0 29 if is_3:
michael@0 30 import io
michael@0 31 else:
michael@0 32 import StringIO
michael@0 33 try:
michael@0 34 import cStringIO
michael@0 35 except ImportError:
michael@0 36 cStringIO = None
michael@0 37
michael@0 38
michael@0 39 __all__ = ['jsmin', 'JavascriptMinify']
michael@0 40 __version__ = '2.0.3'
michael@0 41
michael@0 42
michael@0 43 def jsmin(js):
michael@0 44 """
michael@0 45 returns a minified version of the javascript string
michael@0 46 """
michael@0 47 if not is_3:
michael@0 48 if cStringIO and not isinstance(js, unicode):
michael@0 49 # strings can use cStringIO for a 3x performance
michael@0 50 # improvement, but unicode (in python2) cannot
michael@0 51 klass = cStringIO.StringIO
michael@0 52 else:
michael@0 53 klass = StringIO.StringIO
michael@0 54 else:
michael@0 55 klass = io.StringIO
michael@0 56 ins = klass(js)
michael@0 57 outs = klass()
michael@0 58 JavascriptMinify(ins, outs).minify()
michael@0 59 return outs.getvalue()
michael@0 60
michael@0 61
michael@0 62 class JavascriptMinify(object):
michael@0 63 """
michael@0 64 Minify an input stream of javascript, writing
michael@0 65 to an output stream
michael@0 66 """
michael@0 67
michael@0 68 def __init__(self, instream=None, outstream=None):
michael@0 69 self.ins = instream
michael@0 70 self.outs = outstream
michael@0 71
michael@0 72 def minify(self, instream=None, outstream=None):
michael@0 73 if instream and outstream:
michael@0 74 self.ins, self.outs = instream, outstream
michael@0 75 write = self.outs.write
michael@0 76 read = self.ins.read
michael@0 77
michael@0 78 space_strings = "abcdefghijklmnopqrstuvwxyz"\
michael@0 79 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$\\"
michael@0 80 starters, enders = '{[(+-', '}])+-"\''
michael@0 81 newlinestart_strings = starters + space_strings
michael@0 82 newlineend_strings = enders + space_strings
michael@0 83 do_newline = False
michael@0 84 do_space = False
michael@0 85 doing_single_comment = False
michael@0 86 previous_before_comment = ''
michael@0 87 doing_multi_comment = False
michael@0 88 in_re = False
michael@0 89 in_quote = ''
michael@0 90 quote_buf = []
michael@0 91
michael@0 92 previous = read(1)
michael@0 93 next1 = read(1)
michael@0 94 if previous == '/':
michael@0 95 if next1 == '/':
michael@0 96 doing_single_comment = True
michael@0 97 elif next1 == '*':
michael@0 98 doing_multi_comment = True
michael@0 99 else:
michael@0 100 write(previous)
michael@0 101 elif not previous:
michael@0 102 return
michael@0 103 elif previous >= '!':
michael@0 104 if previous in "'\"":
michael@0 105 in_quote = previous
michael@0 106 write(previous)
michael@0 107 previous_non_space = previous
michael@0 108 else:
michael@0 109 previous_non_space = ' '
michael@0 110 if not next1:
michael@0 111 return
michael@0 112
michael@0 113 while 1:
michael@0 114 next2 = read(1)
michael@0 115 if not next2:
michael@0 116 last = next1.strip()
michael@0 117 if not (doing_single_comment or doing_multi_comment)\
michael@0 118 and last not in ('', '/'):
michael@0 119 write(last)
michael@0 120 break
michael@0 121 if doing_multi_comment:
michael@0 122 if next1 == '*' and next2 == '/':
michael@0 123 doing_multi_comment = False
michael@0 124 next2 = read(1)
michael@0 125 elif doing_single_comment:
michael@0 126 if next1 in '\r\n':
michael@0 127 doing_single_comment = False
michael@0 128 while next2 in '\r\n':
michael@0 129 next2 = read(1)
michael@0 130 if not next2:
michael@0 131 break
michael@0 132 if previous_before_comment in ')}]':
michael@0 133 do_newline = True
michael@0 134 elif previous_before_comment in space_strings:
michael@0 135 write('\n')
michael@0 136 elif in_quote:
michael@0 137 quote_buf.append(next1)
michael@0 138
michael@0 139 if next1 == in_quote:
michael@0 140 numslashes = 0
michael@0 141 for c in reversed(quote_buf[:-1]):
michael@0 142 if c != '\\':
michael@0 143 break
michael@0 144 else:
michael@0 145 numslashes += 1
michael@0 146 if numslashes % 2 == 0:
michael@0 147 in_quote = ''
michael@0 148 write(''.join(quote_buf))
michael@0 149 elif next1 in '\r\n':
michael@0 150 if previous_non_space in newlineend_strings \
michael@0 151 or previous_non_space > '~':
michael@0 152 while 1:
michael@0 153 if next2 < '!':
michael@0 154 next2 = read(1)
michael@0 155 if not next2:
michael@0 156 break
michael@0 157 else:
michael@0 158 if next2 in newlinestart_strings \
michael@0 159 or next2 > '~' or next2 == '/':
michael@0 160 do_newline = True
michael@0 161 break
michael@0 162 elif next1 < '!' and not in_re:
michael@0 163 if (previous_non_space in space_strings \
michael@0 164 or previous_non_space > '~') \
michael@0 165 and (next2 in space_strings or next2 > '~'):
michael@0 166 do_space = True
michael@0 167 elif next1 == '/':
michael@0 168 if in_re:
michael@0 169 if previous != '\\':
michael@0 170 in_re = False
michael@0 171 write('/')
michael@0 172 elif next2 == '/':
michael@0 173 doing_single_comment = True
michael@0 174 previous_before_comment = previous_non_space
michael@0 175 elif next2 == '*':
michael@0 176 doing_multi_comment = True
michael@0 177 else:
michael@0 178 in_re = previous_non_space in '(,=:[?!&|'
michael@0 179 write('/')
michael@0 180 else:
michael@0 181 if do_space:
michael@0 182 do_space = False
michael@0 183 write(' ')
michael@0 184 if do_newline:
michael@0 185 write('\n')
michael@0 186 do_newline = False
michael@0 187 write(next1)
michael@0 188 if not in_re and next1 in "'\"":
michael@0 189 in_quote = next1
michael@0 190 quote_buf = []
michael@0 191 previous = next1
michael@0 192 next1 = next2
michael@0 193
michael@0 194 if previous >= '!':
michael@0 195 previous_non_space = previous

mercurial