jsmin-3.0.0/0000755000076500000240000000000014120710517013264 5ustar tikitustaff00000000000000jsmin-3.0.0/PKG-INFO0000644000076500000240000001715014120710517014365 0ustar tikitustaff00000000000000Metadata-Version: 1.2 Name: jsmin Version: 3.0.0 Summary: JavaScript minifier. Home-page: https://github.com/tikitu/jsmin/ Author: Dave St.Germain Author-email: dave@st.germa.in Maintainer: Tikitu de Jager Maintainer-email: tikitu+jsmin@logophile.org License: MIT License Description: ===== jsmin ===== JavaScript minifier. Usage ===== .. code:: python from jsmin import jsmin with open('myfile.js') as js_file: minified = jsmin(js_file.read()) You can run it as a commandline tool also:: python -m jsmin myfile.js NB: ``jsmin`` makes no attempt to be compatible with `ECMAScript 6 / ES.next / Harmony `_. The current maintainer does not intend to add ES6-compatibility. If you would like to take over maintenance and update ``jsmin`` for ES6, please contact `Tikitu de Jager `_. Pull requests are also welcome, of course, but my time to review them is somewhat limited these days. If you're using ``jsmin`` on ES6 code, though, you might find the ``quote_chars`` parameter useful: .. code:: python from jsmin import jsmin with open('myfile.js') as js_file: minified = jsmin(js_file.read(), quote_chars="'\"`") Where to get it =============== * install the package `from pypi `_ * get the latest release `from latest-release on github `_ * get the development version `from master on github `_ Python 2 support removed ======================== Python 2 support was removed in version 3.0.0. If you need to support Python 2, please use version 2.2.2 with setuptools<58. Contributing ============ `Issues `_ and `Pull requests `_ will be gratefully received on Github. The project used to be hosted `on bitbucket `_ and old issues can still be found there. If possible, please make separate pull requests for tests and for code: tests will be added to the `latest-release` branch while code will go to `master`. Unless you request otherwise, your Github identity will be added to the contributor's list below; if you prefer a different name feel free to add it in your pull request instead. (If you prefer not to be mentioned you'll have to let the maintainer know somehow.) Build/test status ================= Both branches are tested with Travis: https://travis-ci.org/tikitu/jsmin The `latest-release` branch (the version on PyPI plus any new tests) is tested against CPython 3. Currently: .. image:: https://travis-ci.org/tikitu/jsmin.png?branch=latest-release If that branch is failing that means there's a new test that fails on *the latest released version on pypi*, with no fix yet released. The `master` branch (development version, might be ahead of latest released version) is tested against CPython 3. Currently: .. image:: https://travis-ci.org/tikitu/jsmin.png?branch=master If `master` is failing don't use it, but as long as `latest-release` is passing the pypi release should be ok. Contributors (chronological commit order) ========================================= * `Dave St.Germain `_ (original author) * `Hans weltar `_ * `Tikitu de Jager `_ (current maintainer) * https://bitbucket.org/rennat * `Nick Alexander `_ * `Gennady Kovshenin `_ * `Matt Molyneaux `_ * `Albert Wang `_ * `Ben Bradshaw `_ Changelog ========= v3.0.0 (2021-09-08) Ben Bradshaw -------------------------------- - Breaking Change: Removed support for Python 2 - Removed usage of use_2to3 in setup.py v2.2.2 (2017-05-01) Tikitu de Jager ----------------------------------- - Add license headers to code files (fixes i#17) - Remove mercurial files (fixes #20) v2.2.1 (2016-03-06) Tikitu de Jager ----------------------------------- - Fix #14: Infinite loop on `return x / 1;` v2.2.0 (2015-12-19) Tikitu de Jager ----------------------------------- - Merge #13: Preserve "loud comments" starting with `/*!` These are commonly used for copyright notices, and are preserved by various other minifiers (e.g. YUI Compressor). v2.1.6 (2015-10-14) Tikitu de Jager ----------------------------------- - Fix #12: Newline following a regex literal should not be elided. v2.1.5 (2015-10-11) Tikitu de Jager ----------------------------------- - Fix #9: Premature end of statement caused by multi-line comment not adding newline. - Fix #10: Removing multiline comment separating tokens must leave a space. - Refactor comment handling for maintainability. v2.1.4 (2015-08-23) Tikitu de Jager ----------------------------------- - Fix #6: regex literal matching comment was not correctly matched. - Refactor regex literal handling for robustness. v2.1.3 (2015-08-09) Tikitu de Jager ----------------------------------- - Reset issue numbering: issues live in github from now on. - Fix #1: regex literal was not recognised when occurring directly after `{`. v2.1.2 (2015-07-12) Tikitu de Jager ----------------------------------- - Issue numbers here and below refer to the bitbucket repository. - Fix #17: bug when JS starts with comment then literal regex. v2.1.1 (2015-02-14) Tikitu de Jager ----------------------------------- - Fix #16: bug returning a literal regex containing escaped forward-slashes. v2.1.0 (2014-12-24) Tikitu de Jager ----------------------------------- - First changelog entries; see README.rst for prior contributors. - Expose quote_chars parameter to provide just enough unofficial Harmony support to be useful. Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 3 :: Only Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content Classifier: Topic :: Software Development :: Pre-processors Classifier: Topic :: Text Processing :: Filters jsmin-3.0.0/jsmin.egg-info/0000755000076500000240000000000014120710517016076 5ustar tikitustaff00000000000000jsmin-3.0.0/jsmin.egg-info/PKG-INFO0000644000076500000240000001715014120710517017177 0ustar tikitustaff00000000000000Metadata-Version: 1.2 Name: jsmin Version: 3.0.0 Summary: JavaScript minifier. Home-page: https://github.com/tikitu/jsmin/ Author: Dave St.Germain Author-email: dave@st.germa.in Maintainer: Tikitu de Jager Maintainer-email: tikitu+jsmin@logophile.org License: MIT License Description: ===== jsmin ===== JavaScript minifier. Usage ===== .. code:: python from jsmin import jsmin with open('myfile.js') as js_file: minified = jsmin(js_file.read()) You can run it as a commandline tool also:: python -m jsmin myfile.js NB: ``jsmin`` makes no attempt to be compatible with `ECMAScript 6 / ES.next / Harmony `_. The current maintainer does not intend to add ES6-compatibility. If you would like to take over maintenance and update ``jsmin`` for ES6, please contact `Tikitu de Jager `_. Pull requests are also welcome, of course, but my time to review them is somewhat limited these days. If you're using ``jsmin`` on ES6 code, though, you might find the ``quote_chars`` parameter useful: .. code:: python from jsmin import jsmin with open('myfile.js') as js_file: minified = jsmin(js_file.read(), quote_chars="'\"`") Where to get it =============== * install the package `from pypi `_ * get the latest release `from latest-release on github `_ * get the development version `from master on github `_ Python 2 support removed ======================== Python 2 support was removed in version 3.0.0. If you need to support Python 2, please use version 2.2.2 with setuptools<58. Contributing ============ `Issues `_ and `Pull requests `_ will be gratefully received on Github. The project used to be hosted `on bitbucket `_ and old issues can still be found there. If possible, please make separate pull requests for tests and for code: tests will be added to the `latest-release` branch while code will go to `master`. Unless you request otherwise, your Github identity will be added to the contributor's list below; if you prefer a different name feel free to add it in your pull request instead. (If you prefer not to be mentioned you'll have to let the maintainer know somehow.) Build/test status ================= Both branches are tested with Travis: https://travis-ci.org/tikitu/jsmin The `latest-release` branch (the version on PyPI plus any new tests) is tested against CPython 3. Currently: .. image:: https://travis-ci.org/tikitu/jsmin.png?branch=latest-release If that branch is failing that means there's a new test that fails on *the latest released version on pypi*, with no fix yet released. The `master` branch (development version, might be ahead of latest released version) is tested against CPython 3. Currently: .. image:: https://travis-ci.org/tikitu/jsmin.png?branch=master If `master` is failing don't use it, but as long as `latest-release` is passing the pypi release should be ok. Contributors (chronological commit order) ========================================= * `Dave St.Germain `_ (original author) * `Hans weltar `_ * `Tikitu de Jager `_ (current maintainer) * https://bitbucket.org/rennat * `Nick Alexander `_ * `Gennady Kovshenin `_ * `Matt Molyneaux `_ * `Albert Wang `_ * `Ben Bradshaw `_ Changelog ========= v3.0.0 (2021-09-08) Ben Bradshaw -------------------------------- - Breaking Change: Removed support for Python 2 - Removed usage of use_2to3 in setup.py v2.2.2 (2017-05-01) Tikitu de Jager ----------------------------------- - Add license headers to code files (fixes i#17) - Remove mercurial files (fixes #20) v2.2.1 (2016-03-06) Tikitu de Jager ----------------------------------- - Fix #14: Infinite loop on `return x / 1;` v2.2.0 (2015-12-19) Tikitu de Jager ----------------------------------- - Merge #13: Preserve "loud comments" starting with `/*!` These are commonly used for copyright notices, and are preserved by various other minifiers (e.g. YUI Compressor). v2.1.6 (2015-10-14) Tikitu de Jager ----------------------------------- - Fix #12: Newline following a regex literal should not be elided. v2.1.5 (2015-10-11) Tikitu de Jager ----------------------------------- - Fix #9: Premature end of statement caused by multi-line comment not adding newline. - Fix #10: Removing multiline comment separating tokens must leave a space. - Refactor comment handling for maintainability. v2.1.4 (2015-08-23) Tikitu de Jager ----------------------------------- - Fix #6: regex literal matching comment was not correctly matched. - Refactor regex literal handling for robustness. v2.1.3 (2015-08-09) Tikitu de Jager ----------------------------------- - Reset issue numbering: issues live in github from now on. - Fix #1: regex literal was not recognised when occurring directly after `{`. v2.1.2 (2015-07-12) Tikitu de Jager ----------------------------------- - Issue numbers here and below refer to the bitbucket repository. - Fix #17: bug when JS starts with comment then literal regex. v2.1.1 (2015-02-14) Tikitu de Jager ----------------------------------- - Fix #16: bug returning a literal regex containing escaped forward-slashes. v2.1.0 (2014-12-24) Tikitu de Jager ----------------------------------- - First changelog entries; see README.rst for prior contributors. - Expose quote_chars parameter to provide just enough unofficial Harmony support to be useful. Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: MIT License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 3 :: Only Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content Classifier: Topic :: Software Development :: Pre-processors Classifier: Topic :: Text Processing :: Filters jsmin-3.0.0/jsmin.egg-info/SOURCES.txt0000644000076500000240000000035114120710517017761 0ustar tikitustaff00000000000000CHANGELOG.txt LICENSE.txt MANIFEST.in README.rst setup.cfg setup.py jsmin/__init__.py jsmin/__main__.py jsmin/test.py jsmin.egg-info/PKG-INFO jsmin.egg-info/SOURCES.txt jsmin.egg-info/dependency_links.txt jsmin.egg-info/top_level.txtjsmin-3.0.0/jsmin.egg-info/top_level.txt0000644000076500000240000000000614120710517020624 0ustar tikitustaff00000000000000jsmin jsmin-3.0.0/jsmin.egg-info/dependency_links.txt0000644000076500000240000000000114120710517022144 0ustar tikitustaff00000000000000 jsmin-3.0.0/MANIFEST.in0000644000076500000240000000001614120707577015033 0ustar tikitustaff00000000000000include *.txt jsmin-3.0.0/setup.py0000644000076500000240000000230414120710130014764 0ustar tikitustaff00000000000000from setuptools import setup import os, sys, re os.environ['COPYFILE_DISABLE'] = 'true' # this disables including resource forks in tar files on os x def long_description(): return open('README.rst').read() + '\n' + open('CHANGELOG.txt').read() setup( name="jsmin", version=re.search(r'__version__ = ["\']([^"\']+)', open('jsmin/__init__.py').read()).group(1), packages=['jsmin'], description='JavaScript minifier.', long_description=long_description(), author='Dave St.Germain', author_email='dave@st.germa.in', maintainer='Tikitu de Jager', maintainer_email='tikitu+jsmin@logophile.org', test_suite='jsmin.test', license='MIT License', url='https://github.com/tikitu/jsmin/', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Web Environment', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', 'Programming Language :: Python :: 3 :: Only', 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', 'Topic :: Software Development :: Pre-processors', 'Topic :: Text Processing :: Filters', ] ) jsmin-3.0.0/CHANGELOG.txt0000644000076500000240000000413214120710130015303 0ustar tikitustaff00000000000000Changelog ========= v3.0.0 (2021-09-08) Ben Bradshaw -------------------------------- - Breaking Change: Removed support for Python 2 - Removed usage of use_2to3 in setup.py v2.2.2 (2017-05-01) Tikitu de Jager ----------------------------------- - Add license headers to code files (fixes i#17) - Remove mercurial files (fixes #20) v2.2.1 (2016-03-06) Tikitu de Jager ----------------------------------- - Fix #14: Infinite loop on `return x / 1;` v2.2.0 (2015-12-19) Tikitu de Jager ----------------------------------- - Merge #13: Preserve "loud comments" starting with `/*!` These are commonly used for copyright notices, and are preserved by various other minifiers (e.g. YUI Compressor). v2.1.6 (2015-10-14) Tikitu de Jager ----------------------------------- - Fix #12: Newline following a regex literal should not be elided. v2.1.5 (2015-10-11) Tikitu de Jager ----------------------------------- - Fix #9: Premature end of statement caused by multi-line comment not adding newline. - Fix #10: Removing multiline comment separating tokens must leave a space. - Refactor comment handling for maintainability. v2.1.4 (2015-08-23) Tikitu de Jager ----------------------------------- - Fix #6: regex literal matching comment was not correctly matched. - Refactor regex literal handling for robustness. v2.1.3 (2015-08-09) Tikitu de Jager ----------------------------------- - Reset issue numbering: issues live in github from now on. - Fix #1: regex literal was not recognised when occurring directly after `{`. v2.1.2 (2015-07-12) Tikitu de Jager ----------------------------------- - Issue numbers here and below refer to the bitbucket repository. - Fix #17: bug when JS starts with comment then literal regex. v2.1.1 (2015-02-14) Tikitu de Jager ----------------------------------- - Fix #16: bug returning a literal regex containing escaped forward-slashes. v2.1.0 (2014-12-24) Tikitu de Jager ----------------------------------- - First changelog entries; see README.rst for prior contributors. - Expose quote_chars parameter to provide just enough unofficial Harmony support to be useful. jsmin-3.0.0/setup.cfg0000644000076500000240000000007314120710517015105 0ustar tikitustaff00000000000000[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 jsmin-3.0.0/README.rst0000644000076500000240000000662314120710130014751 0ustar tikitustaff00000000000000===== jsmin ===== JavaScript minifier. Usage ===== .. code:: python from jsmin import jsmin with open('myfile.js') as js_file: minified = jsmin(js_file.read()) You can run it as a commandline tool also:: python -m jsmin myfile.js NB: ``jsmin`` makes no attempt to be compatible with `ECMAScript 6 / ES.next / Harmony `_. The current maintainer does not intend to add ES6-compatibility. If you would like to take over maintenance and update ``jsmin`` for ES6, please contact `Tikitu de Jager `_. Pull requests are also welcome, of course, but my time to review them is somewhat limited these days. If you're using ``jsmin`` on ES6 code, though, you might find the ``quote_chars`` parameter useful: .. code:: python from jsmin import jsmin with open('myfile.js') as js_file: minified = jsmin(js_file.read(), quote_chars="'\"`") Where to get it =============== * install the package `from pypi `_ * get the latest release `from latest-release on github `_ * get the development version `from master on github `_ Python 2 support removed ======================== Python 2 support was removed in version 3.0.0. If you need to support Python 2, please use version 2.2.2 with setuptools<58. Contributing ============ `Issues `_ and `Pull requests `_ will be gratefully received on Github. The project used to be hosted `on bitbucket `_ and old issues can still be found there. If possible, please make separate pull requests for tests and for code: tests will be added to the `latest-release` branch while code will go to `master`. Unless you request otherwise, your Github identity will be added to the contributor's list below; if you prefer a different name feel free to add it in your pull request instead. (If you prefer not to be mentioned you'll have to let the maintainer know somehow.) Build/test status ================= Both branches are tested with Travis: https://travis-ci.org/tikitu/jsmin The `latest-release` branch (the version on PyPI plus any new tests) is tested against CPython 3. Currently: .. image:: https://travis-ci.org/tikitu/jsmin.png?branch=latest-release If that branch is failing that means there's a new test that fails on *the latest released version on pypi*, with no fix yet released. The `master` branch (development version, might be ahead of latest released version) is tested against CPython 3. Currently: .. image:: https://travis-ci.org/tikitu/jsmin.png?branch=master If `master` is failing don't use it, but as long as `latest-release` is passing the pypi release should be ok. Contributors (chronological commit order) ========================================= * `Dave St.Germain `_ (original author) * `Hans weltar `_ * `Tikitu de Jager `_ (current maintainer) * https://bitbucket.org/rennat * `Nick Alexander `_ * `Gennady Kovshenin `_ * `Matt Molyneaux `_ * `Albert Wang `_ * `Ben Bradshaw `_ jsmin-3.0.0/jsmin/0000755000076500000240000000000014120710517014404 5ustar tikitustaff00000000000000jsmin-3.0.0/jsmin/__init__.py0000644000076500000240000002037114120710130016507 0ustar tikitustaff00000000000000# vim: set fileencoding=utf-8 : # This code is original from jsmin by Douglas Crockford, it was translated to # Python by Baruch Even. It was rewritten by Dave St.Germain for speed. # # The MIT License (MIT) # # Copyright (c) 2013 Dave St.Germain # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. import io __all__ = ['jsmin', 'JavascriptMinify'] __version__ = '3.0.0' def jsmin(js, **kwargs): """ returns a minified version of the javascript string """ klass = io.StringIO ins = klass(js) outs = klass() JavascriptMinify(ins, outs, **kwargs).minify() return outs.getvalue() class JavascriptMinify(object): """ Minify an input stream of javascript, writing to an output stream """ def __init__(self, instream=None, outstream=None, quote_chars="'\""): self.ins = instream self.outs = outstream self.quote_chars = quote_chars def minify(self, instream=None, outstream=None): if instream and outstream: self.ins, self.outs = instream, outstream self.is_return = False self.return_buf = '' def write(char): # all of this is to support literal regular expressions. # sigh if char in 'return': self.return_buf += char self.is_return = self.return_buf == 'return' else: self.return_buf = '' self.is_return = self.is_return and char < '!' self.outs.write(char) if self.is_return: self.return_buf = '' read = self.ins.read space_strings = "abcdefghijklmnopqrstuvwxyz"\ "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$\\" self.space_strings = space_strings starters, enders = '{[(+-', '}])+-/' + self.quote_chars newlinestart_strings = starters + space_strings + self.quote_chars newlineend_strings = enders + space_strings + self.quote_chars self.newlinestart_strings = newlinestart_strings self.newlineend_strings = newlineend_strings do_newline = False do_space = False escape_slash_count = 0 in_quote = '' quote_buf = [] previous = ';' previous_non_space = ';' next1 = read(1) while next1: next2 = read(1) if in_quote: quote_buf.append(next1) if next1 == in_quote: numslashes = 0 for c in reversed(quote_buf[:-1]): if c != '\\': break else: numslashes += 1 if numslashes % 2 == 0: in_quote = '' write(''.join(quote_buf)) elif next1 in '\r\n': next2, do_newline = self.newline( previous_non_space, next2, do_newline) elif next1 < '!': if (previous_non_space in space_strings \ or previous_non_space > '~') \ and (next2 in space_strings or next2 > '~'): do_space = True elif previous_non_space in '-+' and next2 == previous_non_space: # protect against + ++ or - -- sequences do_space = True elif self.is_return and next2 == '/': # returning a regex... write(' ') elif next1 == '/': if do_space: write(' ') if next2 == '/': # Line comment: treat it as a newline, but skip it next2 = self.line_comment(next1, next2) next1 = '\n' next2, do_newline = self.newline( previous_non_space, next2, do_newline) elif next2 == '*': self.block_comment(next1, next2) next2 = read(1) if previous_non_space in space_strings: do_space = True next1 = previous else: if previous_non_space in '{(,=:[?!&|;' or self.is_return: self.regex_literal(next1, next2) # hackish: after regex literal next1 is still / # (it was the initial /, now it's the last /) next2 = read(1) else: write('/') else: if do_newline: write('\n') do_newline = False do_space = False if do_space: do_space = False write(' ') write(next1) if next1 in self.quote_chars: in_quote = next1 quote_buf = [] if next1 >= '!': previous_non_space = next1 if next1 == '\\': escape_slash_count += 1 else: escape_slash_count = 0 previous = next1 next1 = next2 def regex_literal(self, next1, next2): assert next1 == '/' # otherwise we should not be called! self.return_buf = '' read = self.ins.read write = self.outs.write in_char_class = False write('/') next = next2 while next and (next != '/' or in_char_class): write(next) if next == '\\': write(read(1)) # whatever is next is escaped elif next == '[': write(read(1)) # character class cannot be empty in_char_class = True elif next == ']': in_char_class = False next = read(1) write('/') def line_comment(self, next1, next2): assert next1 == next2 == '/' read = self.ins.read while next1 and next1 not in '\r\n': next1 = read(1) while next1 and next1 in '\r\n': next1 = read(1) return next1 def block_comment(self, next1, next2): assert next1 == '/' assert next2 == '*' read = self.ins.read # Skip past first /* and avoid catching on /*/...*/ next1 = read(1) next2 = read(1) comment_buffer = '/*' while next1 != '*' or next2 != '/': comment_buffer += next1 next1 = next2 next2 = read(1) if comment_buffer.startswith("/*!"): # comment needs preserving self.outs.write(comment_buffer) self.outs.write("*/\n") def newline(self, previous_non_space, next2, do_newline): read = self.ins.read if previous_non_space and ( previous_non_space in self.newlineend_strings or previous_non_space > '~'): while 1: if next2 < '!': next2 = read(1) if not next2: break else: if next2 in self.newlinestart_strings \ or next2 > '~' or next2 == '/': do_newline = True break return next2, do_newline jsmin-3.0.0/jsmin/test.py0000644000076500000240000005455114120707577015763 0ustar tikitustaff00000000000000# vim: set fileencoding=utf-8 : # This code is original from jsmin by Douglas Crockford, it was translated to # Python by Baruch Even. It was rewritten by Dave St.Germain for speed. # # The MIT License (MIT) #· # Copyright (c) 2013 Dave St.Germain #· # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: #· # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. #· # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. import unittest import jsmin class JsTests(unittest.TestCase): def _minify(self, js): return jsmin.jsmin(js) def assertEqual(self, thing1, thing2): if thing1 != thing2: print(repr(thing1), repr(thing2)) raise AssertionError return True def assertMinified(self, js_input, expected, **kwargs): minified = jsmin.jsmin(js_input, **kwargs) assert minified == expected, "\ngot: %r\nexp: %r" % (minified, expected) def testQuoted(self): js = r''' Object.extend(String, { interpret: function(value) { return value == null ? '' : String(value); }, specialChar: { '\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '\\': '\\\\' } }); ''' expected = r"""Object.extend(String,{interpret:function(value){return value==null?'':String(value);},specialChar:{'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','\\':'\\\\'}});""" self.assertMinified(js, expected) def testSingleComment(self): js = r'''// use native browser JS 1.6 implementation if available if (Object.isFunction(Array.prototype.forEach)) Array.prototype._each = Array.prototype.forEach; if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) { // hey there function() {// testing comment foo; //something something location = 'http://foo.com;'; // goodbye } //bye ''' expected = r"""if(Object.isFunction(Array.prototype.forEach)) Array.prototype._each=Array.prototype.forEach;if(!Array.prototype.indexOf)Array.prototype.indexOf=function(item,i){function(){foo;location='http://foo.com;';}""" self.assertMinified(js, expected) def testEmpty(self): self.assertMinified('', '') self.assertMinified(' ', '') self.assertMinified('\n', '') self.assertMinified('\r\n', '') self.assertMinified('\t', '') def testMultiComment(self): js = r""" function foo() { print('hey'); } /* if(this.options.zindex) { this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0); this.element.style.zIndex = this.options.zindex; } */ another thing; """ expected = r"""function foo(){print('hey');} another thing;""" self.assertMinified(js, expected) def testLeadingComment(self): js = r"""/* here is a comment at the top it ends here */ function foo() { alert('crud'); } """ expected = r"""function foo(){alert('crud');}""" self.assertMinified(js, expected) def testBlockCommentStartingWithSlash(self): self.assertMinified('A; /*/ comment */ B', 'A;B') def testBlockCommentEndingWithSlash(self): self.assertMinified('A; /* comment /*/ B', 'A;B') def testLeadingBlockCommentStartingWithSlash(self): self.assertMinified('/*/ comment */ A', 'A') def testLeadingBlockCommentEndingWithSlash(self): self.assertMinified('/* comment /*/ A', 'A') def testEmptyBlockComment(self): self.assertMinified('/**/ A', 'A') def testBlockCommentMultipleOpen(self): self.assertMinified('/* A /* B */ C', 'C') def testJustAComment(self): self.assertMinified(' // a comment', '') def test_issue_bitbucket_10(self): js = ''' files = [{name: value.replace(/^.*\\\\/, '')}]; // comment A ''' expected = '''files=[{name:value.replace(/^.*\\\\/,'')}];A''' self.assertMinified(js, expected) def test_issue_bitbucket_10_without_semicolon(self): js = ''' files = [{name: value.replace(/^.*\\\\/, '')}] // comment A ''' expected = '''files=[{name:value.replace(/^.*\\\\/,'')}]\nA''' self.assertMinified(js, expected) def testRe(self): js = r''' var str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''); return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str); });''' expected = r"""var str=this.replace(/\\./g,'@').replace(/"[^"\\\n\r]*"/g,'');return(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);});""" self.assertMinified(js, expected) def testIgnoreComment(self): js = r""" var options_for_droppable = { overlap: options.overlap, containment: options.containment, tree: options.tree, hoverclass: options.hoverclass, onHover: Sortable.onHover } var options_for_tree = { onHover: Sortable.onEmptyHover, overlap: options.overlap, containment: options.containment, hoverclass: options.hoverclass } // fix for gecko engine Element.cleanWhitespace(element); """ expected = r"""var options_for_droppable={overlap:options.overlap,containment:options.containment,tree:options.tree,hoverclass:options.hoverclass,onHover:Sortable.onHover} var options_for_tree={onHover:Sortable.onEmptyHover,overlap:options.overlap,containment:options.containment,hoverclass:options.hoverclass} Element.cleanWhitespace(element);""" self.assertMinified(js, expected) def testHairyRe(self): js = r""" inspect: function(useDoubleQuotes) { var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) { var character = String.specialChar[match[0]]; return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16); }); if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; return "'" + escapedString.replace(/'/g, '\\\'') + "'"; }, toJSON: function() { return this.inspect(true); }, unfilterJSON: function(filter) { return this.sub(filter || Prototype.JSONFilter, '#{1}'); }, """ expected = r"""inspect:function(useDoubleQuotes){var escapedString=this.gsub(/[\x00-\x1f\\]/,function(match){var character=String.specialChar[match[0]];return character?character:'\\u00'+match[0].charCodeAt().toPaddedString(2,16);});if(useDoubleQuotes)return'"'+escapedString.replace(/"/g,'\\"')+'"';return"'"+escapedString.replace(/'/g,'\\\'')+"'";},toJSON:function(){return this.inspect(true);},unfilterJSON:function(filter){return this.sub(filter||Prototype.JSONFilter,'#{1}');},""" self.assertMinified(js, expected) def testLiteralRe(self): js = r""" myString.replace(/\\/g, '/'); console.log("hi"); """ expected = r"""myString.replace(/\\/g,'/');console.log("hi");""" self.assertMinified(js, expected) js = r''' return /^data:image\//i.test(url) || /^(https?|ftp|file|about|chrome|resource):/.test(url); ''' expected = r'''return /^data:image\//i.test(url)||/^(https?|ftp|file|about|chrome|resource):/.test(url);''' self.assertMinified(js, expected) def testNoBracesWithComment(self): js = r""" onSuccess: function(transport) { var js = transport.responseText.strip(); if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check throw 'Server returned an invalid collection representation.'; this._collection = eval(js); this.checkForExternalText(); }.bind(this), onFailure: this.onFailure }); """ expected = r"""onSuccess:function(transport){var js=transport.responseText.strip();if(!/^\[.*\]$/.test(js)) throw'Server returned an invalid collection representation.';this._collection=eval(js);this.checkForExternalText();}.bind(this),onFailure:this.onFailure});""" self.assertMinified(js, expected) js_without_comment = r""" onSuccess: function(transport) { var js = transport.responseText.strip(); if (!/^\[.*\]$/.test(js)) throw 'Server returned an invalid collection representation.'; this._collection = eval(js); this.checkForExternalText(); }.bind(this), onFailure: this.onFailure }); """ self.assertMinified(js_without_comment, expected) def testSpaceInRe(self): js = r""" num = num.replace(/ /g,''); """ self.assertMinified(js, "num=num.replace(/ /g,'');") def testEmptyString(self): js = r''' function foo('') { } ''' self.assertMinified(js, "function foo(''){}") def testDoubleSpace(self): js = r''' var foo = "hey"; ''' self.assertMinified(js, 'var foo="hey";') def testLeadingRegex(self): js = r'/[d]+/g ' self.assertMinified(js, js.strip()) def testLeadingString(self): js = r"'a string in the middle of nowhere'; // and a comment" self.assertMinified(js, "'a string in the middle of nowhere';") def testSingleCommentEnd(self): js = r'// a comment\n' self.assertMinified(js, '') def testInputStream(self): try: from StringIO import StringIO except ImportError: from io import StringIO ins = StringIO(r''' function foo('') { } ''') outs = StringIO() m = jsmin.JavascriptMinify() m.minify(ins, outs) output = outs.getvalue() assert output == "function foo(''){}" def testUnicode(self): instr = u'\u4000 //foo' expected = u'\u4000' output = jsmin.jsmin(instr) self.assertEqual(output, expected) def testCommentBeforeEOF(self): self.assertMinified("//test\r\n", "") def testCommentInObj(self): self.assertMinified("""{ a: 1,//comment }""", "{a:1,}") def testCommentInObj2(self): self.assertMinified("{a: 1//comment\r\n}", "{a:1}") def testImplicitSemicolon(self): # return \n 1 is equivalent with return; 1 # so best make sure jsmin retains the newline self.assertMinified("return\na", "return\na") def test_explicit_semicolon(self): self.assertMinified("return;//comment\r\na", "return;a") def testImplicitSemicolon2(self): self.assertMinified("return//comment...\r\nar", "return\nar") def testImplicitSemicolon3(self): self.assertMinified("return//comment...\r\na", "return\na") def testSingleComment2(self): self.assertMinified('x.replace(/\//, "_")// slash to underscore', 'x.replace(/\//,"_")') def testSlashesNearComments(self): original = ''' { a: n / 2, } // comment ''' expected = '''{a:n/2,}''' self.assertMinified(original, expected) def testReturn(self): original = ''' return foo;//comment return bar;''' expected = 'return foo;return bar;' self.assertMinified(original, expected) original = ''' return foo return bar;''' expected = 'return foo\nreturn bar;' self.assertMinified(original, expected) def test_space_plus(self): original = '"s" + ++e + "s"' expected = '"s"+ ++e+"s"' self.assertMinified(original, expected) def test_no_final_newline(self): original = '"s"' expected = '"s"' self.assertMinified(original, expected) def test_space_with_regex_repeats(self): original = '/(NaN| {2}|^$)/.test(a)&&(a="M 0 0");' self.assertMinified(original, original) # there should be nothing jsmin can do here def test_space_with_regex_repeats_not_at_start(self): original = 'aaa;/(NaN| {2}|^$)/.test(a)&&(a="M 0 0");' self.assertMinified(original, original) # there should be nothing jsmin can do here def test_space_in_regex(self): original = '/a (a)/.test("a")' self.assertMinified(original, original) def test_brackets_around_slashed_regex(self): original = 'function a() { /\//.test("a") }' expected = 'function a(){/\//.test("a")}' self.assertMinified(original, expected) def test_angular_1(self): original = '''var /** holds major version number for IE or NaN for real browsers */ msie, jqLite, // delay binding since jQuery could be loaded after us.''' minified = jsmin.jsmin(original) self.assertTrue('var\nmsie' in minified) def test_angular_2(self): original = 'var/* comment */msie;' expected = 'var msie;' self.assertMinified(original, expected) def test_angular_3(self): original = 'var /* comment */msie;' expected = 'var msie;' self.assertMinified(original, expected) def test_angular_4(self): original = 'var /* comment */ msie;' expected = 'var msie;' self.assertMinified(original, expected) def test_angular_5(self): original = 'a/b' self.assertMinified(original, original) def testBackticks(self): original = '`test`' self.assertMinified(original, original, quote_chars="'\"`") original = '` test with leading whitespace`' self.assertMinified(original, original, quote_chars="'\"`") original = '`test with trailing whitespace `' self.assertMinified(original, original, quote_chars="'\"`") original = '''`test with a new line`''' self.assertMinified(original, original, quote_chars="'\"`") original = '''dumpAvStats: function(stats) { var statsString = ""; if (stats.mozAvSyncDelay) { statsString += `A/V sync: ${stats.mozAvSyncDelay} ms `; } if (stats.mozJitterBufferDelay) { statsString += `Jitter-buffer delay: ${stats.mozJitterBufferDelay} ms`; } return React.DOM.div(null, statsString);''' expected = 'dumpAvStats:function(stats){var statsString="";if(stats.mozAvSyncDelay){statsString+=`A/V sync: ${stats.mozAvSyncDelay} ms `;}\nif(stats.mozJitterBufferDelay){statsString+=`Jitter-buffer delay: ${stats.mozJitterBufferDelay} ms`;}\nreturn React.DOM.div(null,statsString);' self.assertMinified(original, expected, quote_chars="'\"`") def testBackticksExpressions(self): original = '`Fifteen is ${a + b} and not ${2 * a + b}.`' self.assertMinified(original, original, quote_chars="'\"`") original = '''`Fifteen is ${a + b} and not ${2 * a + "b"}.`''' self.assertMinified(original, original, quote_chars="'\"`") def testBackticksTagged(self): original = 'tag`Hello ${ a + b } world ${ a * b}`;' self.assertMinified(original, original, quote_chars="'\"`") def test_issue_bitbucket_16(self): original = """ f = function() { return /DataTree\/(.*)\//.exec(this._url)[1]; } """ self.assertMinified( original, 'f=function(){return /DataTree\/(.*)\//.exec(this._url)[1];}') def test_issue_bitbucket_17(self): original = "// hi\n/^(get|post|head|put)$/i.test('POST')" self.assertMinified(original, "/^(get|post|head|put)$/i.test('POST')") def test_issue_6(self): original = ''' respond.regex = { comments: /\/\*[^*]*\*+([^/][^*]*\*+)*\//gi, urls: 'whatever' }; ''' expected = original.replace(' ', '').replace('\n', '') self.assertMinified(original, expected) def test_issue_9(self): original = '\n'.join([ 'var a = \'hi\' // this is a comment', 'var a = \'hi\' /* this is also a comment */', 'console.log(1) // this is a comment', 'console.log(1) /* this is also a comment */', '1 // this is a comment', '1 /* this is also a comment */', '{} // this is a comment', '{} /* this is also a comment */', '"YOLO" /* this is a comment */', '"YOLO" // this is a comment', '(1 + 2) // comment', '(1 + 2) /* yup still comment */', 'var b' ]) expected = '\n'.join([ 'var a=\'hi\'', 'var a=\'hi\'', 'console.log(1)', 'console.log(1)', '1', '1', '{}', '{}', '"YOLO"', '"YOLO"', '(1+2)', '(1+2)', 'var b' ]) self.assertMinified(expected, expected) self.assertMinified(original, expected) def test_newline_between_strings(self): self.assertMinified('"yolo"\n"loyo"', '"yolo"\n"loyo"') def test_issue_10_comments_between_tokens(self): self.assertMinified('var/* comment */a', 'var a') def test_ends_with_string(self): self.assertMinified('var s = "s"', 'var s="s"') def test_short_comment(self): self.assertMinified('a;/**/b', 'a;b') def test_shorter_comment(self): self.assertMinified('a;/*/*/b', 'a;b') def test_block_comment_with_semicolon(self): self.assertMinified('a;/**/\nb', 'a;b') def test_block_comment_With_implicit_semicolon(self): self.assertMinified('a/**/\nvar b', 'a\nvar b') def test_issue_9_single_comments(self): original = ''' var a = "hello" // this is a comment a += " world" ''' self.assertMinified(original, 'var a="hello"\na+=" world"') def test_issue_9_multi_comments(self): original = ''' var a = "hello" /* this is a comment */ a += " world" ''' self.assertMinified(original, 'var a="hello"\na+=" world"') def test_issue_12_re_nl_if(self): original = ''' var re = /\d{4}/ if (1) { console.log(2); }''' self.assertMinified( original, 'var re=/\d{4}/\nif(1){console.log(2);}') def test_issue_12_re_nl_other(self): original = ''' var re = /\d{4}/ g = 10''' self.assertMinified(original , 'var re=/\d{4}/\ng=10') def test_preserve_copyright(self): original = ''' function this() { /*! Copyright year person */ console.log('hello!'); } /*! Copyright blah blah * * Some other text */ var a; ''' expected = """function this(){/*! Copyright year person */ console.log('hello!');}/*! Copyright blah blah * * Some other text */\n\nvar a;""" self.assertMinified(original, expected) def test_issue_14(self): original = 'return x / 1;' self.assertMinified(original, 'return x/1;') def test_issue_14_with_char_from_return(self): original = 'return r / 1;' self.assertMinified(original, 'return r/1;') class RegexTests(unittest.TestCase): def regex_recognise(self, js): if not jsmin.is_3: if jsmin.cStringIO and not isinstance(js, unicode): # strings can use cStringIO for a 3x performance # improvement, but unicode (in python2) cannot klass = jsmin.cStringIO.StringIO else: klass = jsmin.StringIO.StringIO else: klass = jsmin.io.StringIO ins = klass(js[2:]) outs = klass() jsmin.JavascriptMinify(ins, outs).regex_literal(js[0], js[1]) return outs.getvalue() def assert_regex(self, js_input, expected): assert js_input[0] == '/' # otherwise we should not be testing! recognised = self.regex_recognise(js_input) assert recognised == expected, "\n in: %r\ngot: %r\nexp: %r" % (js_input, recognised, expected) def test_simple(self): self.assert_regex('/123/g', '/123/') def test_character_class(self): self.assert_regex('/a[0-9]b/g', '/a[0-9]b/') def test_character_class_with_slash(self): self.assert_regex('/a[/]b/g', '/a[/]b/') def test_escaped_forward_slash(self): self.assert_regex(r'/a\/b/g', r'/a\/b/') def test_escaped_back_slash(self): self.assert_regex(r'/a\\/g', r'/a\\/') def test_empty_character_class(self): # This one is subtle: an empty character class is not allowed, afaics # from http://regexpal.com/ Chrome Version 44.0.2403.155 (64-bit) Mac # so this char class is interpreted as containing ]/ *not* as char # class [] followed by end-of-regex /. self.assert_regex('/a[]/]b/g', '/a[]/]b/') def test_precedence_of_parens(self): # judging from # http://regexpal.com/ Chrome Version 44.0.2403.155 (64-bit) Mac # () have lower precedence than [] self.assert_regex('/a([)])b/g', '/a([)])b/') self.assert_regex('/a[(]b/g', '/a[(]b/') if __name__ == '__main__': unittest.main() jsmin-3.0.0/jsmin/__main__.py0000644000076500000240000000300214120707577016505 0ustar tikitustaff00000000000000# vim: set fileencoding=utf-8 : # This code is original from jsmin by Douglas Crockford, it was translated to # Python by Baruch Even. It was rewritten by Dave St.Germain for speed. # # The MIT License (MIT) #· # Copyright (c) 2013 Dave St.Germain #· # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: #· # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. #· # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. import sys, os, glob from jsmin import JavascriptMinify for f in sys.argv[1:]: with open(f, 'r') as js: minifier = JavascriptMinify(js, sys.stdout) minifier.minify() sys.stdout.write('\n') jsmin-3.0.0/LICENSE.txt0000644000076500000240000000207414120707577015126 0ustar tikitustaff00000000000000The MIT License (MIT) Copyright (c) 2013 Dave St.Germain Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.