Remove rcssmin and rjsmin from the repo and make them proper dependencies. ref #664
This commit is contained in:
parent
7eca920548
commit
6f4639e6b1
2
Makefile
2
Makefile
|
@ -10,7 +10,7 @@ runtests:
|
|||
coverage run --branch --source=compressor `which django-admin.py` test --settings=compressor.test_settings compressor
|
||||
|
||||
coveragereport:
|
||||
coverage report --omit=compressor/test*,compressor/filters/jsmin/rjsmin*,compressor/filters/cssmin/cssmin*
|
||||
coverage report --omit=compressor/test*
|
||||
|
||||
test: flake8 runtests coveragereport
|
||||
|
||||
|
|
|
@ -11,7 +11,8 @@ class CSSCompressorFilter(CallbackOutputFilter):
|
|||
|
||||
|
||||
class rCSSMinFilter(CallbackOutputFilter):
|
||||
callback = "compressor.filters.cssmin.rcssmin.cssmin"
|
||||
callback = "rcssmin.cssmin"
|
||||
dependencies = ["rcssmin"]
|
||||
kwargs = {
|
||||
"keep_bang_comments": True
|
||||
}
|
||||
|
|
|
@ -1,374 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: ascii -*-
|
||||
r"""
|
||||
==============
|
||||
CSS Minifier
|
||||
==============
|
||||
|
||||
CSS Minifier.
|
||||
|
||||
The minifier is based on the semantics of the `YUI compressor`_\\, which
|
||||
itself is based on `the rule list by Isaac Schlueter`_\\.
|
||||
|
||||
: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.
|
||||
|
||||
This module is a re-implementation aiming for speed instead of maximum
|
||||
compression, so it can be used at runtime (rather than during a preprocessing
|
||||
step). RCSSmin does syntactical compression only (removing spaces, comments
|
||||
and possibly semicolons). It does not provide semantic compression (like
|
||||
removing empty blocks, collapsing redundant properties etc). It does, however,
|
||||
support various CSS hacks (by keeping them working as intended).
|
||||
|
||||
Here's a feature list:
|
||||
|
||||
- Strings are kept, except that escaped newlines are stripped
|
||||
- Space/Comments before the very end or before various characters are
|
||||
stripped: ``:{});=>],!`` (The colon (``:``) is a special case, a single
|
||||
space is kept if it's outside a ruleset.)
|
||||
- Space/Comments at the very beginning or after various characters are
|
||||
stripped: ``{}(=:>[,!``
|
||||
- Optional space after unicode escapes is kept, resp. replaced by a simple
|
||||
space
|
||||
- whitespaces inside ``url()`` definitions are stripped
|
||||
- Comments starting with an exclamation mark (``!``) can be kept optionally.
|
||||
- All other comments and/or whitespace characters are replaced by a single
|
||||
space.
|
||||
- Multiple consecutive semicolons are reduced to one
|
||||
- The last semicolon within a ruleset is stripped
|
||||
- CSS Hacks supported:
|
||||
|
||||
- IE7 hack (``>/**/``)
|
||||
- Mac-IE5 hack (``/*\\*/.../**/``)
|
||||
- The boxmodelhack is supported naturally because it relies on valid CSS2
|
||||
strings
|
||||
- Between ``:first-line`` and the following comma or curly brace a space is
|
||||
inserted. (apparently it's needed for IE6)
|
||||
- Same for ``:first-letter``
|
||||
|
||||
rcssmin.c is a reimplementation of rcssmin.py in C and improves runtime up to
|
||||
factor 100 or so (depending on the input). docs/BENCHMARKS in the source
|
||||
distribution contains the details.
|
||||
|
||||
Both python 2 (>= 2.4) and python 3 are supported.
|
||||
|
||||
.. _YUI compressor: https://github.com/yui/yuicompressor/
|
||||
|
||||
.. _the rule list by Isaac Schlueter: https://github.com/isaacs/cssmin/
|
||||
"""
|
||||
if __doc__:
|
||||
# pylint: disable = W0622
|
||||
__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.6'
|
||||
__all__ = ['cssmin']
|
||||
|
||||
import re as _re
|
||||
|
||||
|
||||
def _make_cssmin(python_only=False):
|
||||
"""
|
||||
Generate CSS minifier.
|
||||
|
||||
: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 = R0912, R0914, W0612
|
||||
|
||||
if not python_only:
|
||||
try:
|
||||
import _rcssmin
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
return _rcssmin.cssmin
|
||||
|
||||
nl = r'(?:[\n\f]|\r\n?)' # pylint: disable = C0103
|
||||
spacechar = r'[\r\n\f\040\t]'
|
||||
|
||||
unicoded = r'[0-9a-fA-F]{1,6}(?:[\040\n\t\f]|\r\n?)?'
|
||||
escaped = r'[^\n\r\f0-9a-fA-F]'
|
||||
escape = r'(?:\\(?:%(unicoded)s|%(escaped)s))' % locals()
|
||||
|
||||
nmchar = r'[^\000-\054\056\057\072-\100\133-\136\140\173-\177]'
|
||||
# nmstart = r'[^\000-\100\133-\136\140\173-\177]'
|
||||
# ident = (r'(?:'
|
||||
# r'-?(?:%(nmstart)s|%(escape)s)%(nmchar)s*(?:%(escape)s%(nmchar)s*)*'
|
||||
# r')') % locals()
|
||||
|
||||
comment = r'(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)'
|
||||
|
||||
# only for specific purposes. The bang is grouped:
|
||||
_bang_comment = r'(?:/\*(!?)[^*]*\*+(?:[^/*][^*]*\*+)*/)'
|
||||
|
||||
string1 = \
|
||||
r'(?:\047[^\047\\\r\n\f]*(?:\\[^\r\n\f][^\047\\\r\n\f]*)*\047)'
|
||||
string2 = r'(?:"[^"\\\r\n\f]*(?:\\[^\r\n\f][^"\\\r\n\f]*)*")'
|
||||
strings = r'(?:%s|%s)' % (string1, string2)
|
||||
|
||||
nl_string1 = \
|
||||
r'(?:\047[^\047\\\r\n\f]*(?:\\(?:[^\r]|\r\n?)[^\047\\\r\n\f]*)*\047)'
|
||||
nl_string2 = r'(?:"[^"\\\r\n\f]*(?:\\(?:[^\r]|\r\n?)[^"\\\r\n\f]*)*")'
|
||||
nl_strings = r'(?:%s|%s)' % (nl_string1, nl_string2)
|
||||
|
||||
uri_nl_string1 = r'(?:\047[^\047\\]*(?:\\(?:[^\r]|\r\n?)[^\047\\]*)*\047)'
|
||||
uri_nl_string2 = r'(?:"[^"\\]*(?:\\(?:[^\r]|\r\n?)[^"\\]*)*")'
|
||||
uri_nl_strings = r'(?:%s|%s)' % (uri_nl_string1, uri_nl_string2)
|
||||
|
||||
nl_escaped = r'(?:\\%(nl)s)' % locals()
|
||||
|
||||
space = r'(?:%(spacechar)s|%(comment)s)' % locals()
|
||||
|
||||
ie7hack = r'(?:>/\*\*/)'
|
||||
|
||||
uri = (r'(?:'
|
||||
# noqa pylint: disable = C0330
|
||||
r'(?:[^\000-\040"\047()\\\177]*'
|
||||
r'(?:%(escape)s[^\000-\040"\047()\\\177]*)*)'
|
||||
r'(?:'
|
||||
r'(?:%(spacechar)s+|%(nl_escaped)s+)'
|
||||
r'(?:'
|
||||
r'(?:[^\000-\040"\047()\\\177]|%(escape)s|%(nl_escaped)s)'
|
||||
r'[^\000-\040"\047()\\\177]*'
|
||||
r'(?:%(escape)s[^\000-\040"\047()\\\177]*)*'
|
||||
r')+'
|
||||
r')*'
|
||||
r')') % locals()
|
||||
|
||||
nl_unesc_sub = _re.compile(nl_escaped).sub
|
||||
|
||||
uri_space_sub = _re.compile((
|
||||
r'(%(escape)s+)|%(spacechar)s+|%(nl_escaped)s+'
|
||||
) % locals()).sub
|
||||
uri_space_subber = lambda m: m.groups()[0] or ''
|
||||
|
||||
space_sub_simple = _re.compile((
|
||||
r'[\r\n\f\040\t;]+|(%(comment)s+)'
|
||||
) % locals()).sub
|
||||
space_sub_banged = _re.compile((
|
||||
r'[\r\n\f\040\t;]+|(%(_bang_comment)s+)'
|
||||
) % locals()).sub
|
||||
|
||||
post_esc_sub = _re.compile(r'[\r\n\f\t]+').sub
|
||||
|
||||
main_sub = _re.compile((
|
||||
# noqa pylint: disable = C0330
|
||||
r'([^\\"\047u>@\r\n\f\040\t/;:{}+]+)' # 1
|
||||
r'|(?<=[{}(=:>[,!])(%(space)s+)' # 2
|
||||
r'|^(%(space)s+)' # 3
|
||||
r'|(%(space)s+)(?=(([:{});=>\],!])|$)?)' # 4, 5, 6
|
||||
r'|;(%(space)s*(?:;%(space)s*)*)(?=(\})?)' # 7, 8
|
||||
r'|(\{)' # 9
|
||||
r'|(\})' # 10
|
||||
r'|(%(strings)s)' # 11
|
||||
r'|(?<!%(nmchar)s)url\(%(spacechar)s*(' # 12
|
||||
r'%(uri_nl_strings)s'
|
||||
r'|%(uri)s'
|
||||
r')%(spacechar)s*\)'
|
||||
r'|(@(?:' # 13
|
||||
r'[mM][eE][dD][iI][aA]'
|
||||
r'|[sS][uU][pP][pP][oO][rR][tT][sS]'
|
||||
r'|[dD][oO][cC][uU][mM][eE][nN][tT]'
|
||||
r'|(?:-(?:'
|
||||
r'[wW][eE][bB][kK][iI][tT]|[mM][oO][zZ]|[oO]|[mM][sS]'
|
||||
r')-)?'
|
||||
r'[kK][eE][yY][fF][rR][aA][mM][eE][sS]'
|
||||
r'))(?!%(nmchar)s)'
|
||||
r'|(%(ie7hack)s)(%(space)s*)' # 14, 15
|
||||
r'|(:[fF][iI][rR][sS][tT]-[lL]' # 16
|
||||
r'(?:[iI][nN][eE]|[eE][tT][tT][eE][rR]))'
|
||||
r'(%(space)s*)(?=[{,])' # 17
|
||||
r'|(%(nl_strings)s)' # 18
|
||||
r'|(%(escape)s[^\\"\047u>@\r\n\f\040\t/;:{}+]*)' # 19
|
||||
) % locals()).sub
|
||||
|
||||
# print main_sub.__self__.pattern
|
||||
|
||||
def main_subber(keep_bang_comments):
|
||||
""" Make main subber """
|
||||
in_macie5, in_rule, at_group = [0], [0], [0]
|
||||
|
||||
if keep_bang_comments:
|
||||
space_sub = space_sub_banged
|
||||
|
||||
def space_subber(match):
|
||||
""" Space|Comment subber """
|
||||
if match.lastindex:
|
||||
group1, group2 = match.group(1, 2)
|
||||
if group2:
|
||||
if group1.endswith(r'\*/'):
|
||||
in_macie5[0] = 1
|
||||
else:
|
||||
in_macie5[0] = 0
|
||||
return group1
|
||||
elif group1:
|
||||
if group1.endswith(r'\*/'):
|
||||
if in_macie5[0]:
|
||||
return ''
|
||||
in_macie5[0] = 1
|
||||
return r'/*\*/'
|
||||
elif in_macie5[0]:
|
||||
in_macie5[0] = 0
|
||||
return '/**/'
|
||||
return ''
|
||||
else:
|
||||
space_sub = space_sub_simple
|
||||
|
||||
def space_subber(match):
|
||||
""" Space|Comment subber """
|
||||
if match.lastindex:
|
||||
if match.group(1).endswith(r'\*/'):
|
||||
if in_macie5[0]:
|
||||
return ''
|
||||
in_macie5[0] = 1
|
||||
return r'/*\*/'
|
||||
elif in_macie5[0]:
|
||||
in_macie5[0] = 0
|
||||
return '/**/'
|
||||
return ''
|
||||
|
||||
def fn_space_post(group):
|
||||
""" space with token after """
|
||||
if group(5) is None or (
|
||||
group(6) == ':' and not in_rule[0] and not at_group[0]):
|
||||
return ' ' + space_sub(space_subber, group(4))
|
||||
return space_sub(space_subber, group(4))
|
||||
|
||||
def fn_semicolon(group):
|
||||
""" ; handler """
|
||||
return ';' + space_sub(space_subber, group(7))
|
||||
|
||||
def fn_semicolon2(group):
|
||||
""" ; handler """
|
||||
if in_rule[0]:
|
||||
return space_sub(space_subber, group(7))
|
||||
return ';' + space_sub(space_subber, group(7))
|
||||
|
||||
def fn_open(_):
|
||||
""" { handler """
|
||||
if at_group[0]:
|
||||
at_group[0] -= 1
|
||||
else:
|
||||
in_rule[0] = 1
|
||||
return '{'
|
||||
|
||||
def fn_close(_):
|
||||
""" } handler """
|
||||
in_rule[0] = 0
|
||||
return '}'
|
||||
|
||||
def fn_at_group(group):
|
||||
""" @xxx group handler """
|
||||
at_group[0] += 1
|
||||
return group(13)
|
||||
|
||||
def fn_ie7hack(group):
|
||||
""" IE7 Hack handler """
|
||||
if not in_rule[0] and not at_group[0]:
|
||||
in_macie5[0] = 0
|
||||
return group(14) + space_sub(space_subber, group(15))
|
||||
return '>' + space_sub(space_subber, group(15))
|
||||
|
||||
table = (
|
||||
# noqa pylint: disable = C0330
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
fn_space_post, # space with token after
|
||||
fn_space_post, # space with token after
|
||||
fn_space_post, # space with token after
|
||||
fn_semicolon, # semicolon
|
||||
fn_semicolon2, # semicolon
|
||||
fn_open, # {
|
||||
fn_close, # }
|
||||
lambda g: g(11), # string
|
||||
lambda g: 'url(%s)' % uri_space_sub(uri_space_subber, g(12)),
|
||||
# url(...)
|
||||
fn_at_group, # @xxx expecting {...}
|
||||
None,
|
||||
fn_ie7hack, # ie7hack
|
||||
None,
|
||||
lambda g: g(16) + ' ' + space_sub(space_subber, g(17)),
|
||||
# :first-line|letter followed
|
||||
# by [{,] (apparently space
|
||||
# needed for IE6)
|
||||
lambda g: nl_unesc_sub('', g(18)), # nl_string
|
||||
lambda g: post_esc_sub(' ', g(19)), # escape
|
||||
)
|
||||
|
||||
def func(match):
|
||||
""" Main subber """
|
||||
idx, group = match.lastindex, match.group
|
||||
if idx > 3:
|
||||
return table[idx](group)
|
||||
|
||||
# shortcuts for frequent operations below:
|
||||
elif idx == 1: # not interesting
|
||||
return group(1)
|
||||
# else: # space with token before or at the beginning
|
||||
return space_sub(space_subber, group(idx))
|
||||
|
||||
return func
|
||||
|
||||
def cssmin(style, keep_bang_comments=False): # pylint: disable = W0621
|
||||
"""
|
||||
Minify CSS.
|
||||
|
||||
:Parameters:
|
||||
`style` : ``str``
|
||||
CSS to minify
|
||||
|
||||
`keep_bang_comments` : ``bool``
|
||||
Keep comments starting with an exclamation mark? (``/*!...*/``)
|
||||
|
||||
:Return: Minified style
|
||||
:Rtype: ``str``
|
||||
"""
|
||||
return main_sub(main_subber(keep_bang_comments), style)
|
||||
|
||||
return cssmin
|
||||
|
||||
cssmin = _make_cssmin()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
def main():
|
||||
""" Main """
|
||||
import sys as _sys
|
||||
keep_bang_comments = (
|
||||
'-b' in _sys.argv[1:]
|
||||
or '-bp' in _sys.argv[1:]
|
||||
or '-pb' in _sys.argv[1:]
|
||||
)
|
||||
if '-p' in _sys.argv[1:] or '-bp' in _sys.argv[1:] \
|
||||
or '-pb' in _sys.argv[1:]:
|
||||
global cssmin # pylint: disable = W0603
|
||||
cssmin = _make_cssmin(python_only=True)
|
||||
_sys.stdout.write(cssmin(
|
||||
_sys.stdin.read(), keep_bang_comments=keep_bang_comments
|
||||
))
|
||||
main()
|
|
@ -4,7 +4,8 @@ from compressor.filters.jsmin.slimit import SlimItFilter # noqa
|
|||
|
||||
|
||||
class rJSMinFilter(CallbackOutputFilter):
|
||||
callback = "compressor.filters.jsmin.rjsmin.jsmin"
|
||||
callback = "rjsmin.jsmin"
|
||||
dependencies = ["rjsmin"]
|
||||
kwargs = {
|
||||
"keep_bang_comments": True
|
||||
}
|
||||
|
|
|
@ -1,514 +0,0 @@
|
|||
#!/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]*)*")'
|
||||
strings = r'(?:%s|%s)' % (string1, string2)
|
||||
|
||||
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()
|
|
@ -130,7 +130,7 @@ Backend settings
|
|||
- ``compressor.filters.cssmin.rCSSMinFilter``
|
||||
|
||||
A filter that uses the cssmin implementation rCSSmin_ to compress CSS
|
||||
(included, no external dependencies).
|
||||
(installed by default).
|
||||
|
||||
- ``compressor.filters.cleancss.CleanCSSFilter``
|
||||
|
||||
|
@ -173,7 +173,7 @@ Backend settings
|
|||
- ``compressor.filters.jsmin.JSMinFilter``
|
||||
|
||||
A filter that uses the jsmin implementation rJSmin_ to compress
|
||||
JavaScript code (included, no external dependencies).
|
||||
JavaScript code (installed by default).
|
||||
|
||||
.. _slimit_filter:
|
||||
|
||||
|
|
|
@ -11,3 +11,5 @@ jingo==0.7
|
|||
django-sekizai==0.8.2
|
||||
django-overextends==0.4.0
|
||||
csscompressor==0.9.4
|
||||
rcssmin==1.0.6
|
||||
rjsmin==1.0.12
|
||||
|
|
2
setup.py
2
setup.py
|
@ -142,5 +142,7 @@ setup(
|
|||
zip_safe=False,
|
||||
install_requires=[
|
||||
'django-appconf >= 0.4',
|
||||
'rcssmin == 1.0.6',
|
||||
'rjsmin == 1.0.12',
|
||||
],
|
||||
)
|
||||
|
|
8
tox.ini
8
tox.ini
|
@ -13,6 +13,8 @@ two =
|
|||
django-sekizai==0.8.2
|
||||
django-overextends==0.4.0
|
||||
csscompressor==0.9.4
|
||||
rcssmin==1.0.6
|
||||
rjsmin==1.0.12
|
||||
two_six =
|
||||
flake8==2.4.0
|
||||
coverage==3.7.1
|
||||
|
@ -27,6 +29,8 @@ two_six =
|
|||
django-sekizai==0.8.2
|
||||
django-overextends==0.4.0
|
||||
csscompressor==0.9.4
|
||||
rcssmin==1.0.6
|
||||
rjsmin==1.0.12
|
||||
three =
|
||||
flake8==2.4.0
|
||||
coverage==3.7.1
|
||||
|
@ -40,6 +44,8 @@ three =
|
|||
django-sekizai==0.8.2
|
||||
django-overextends==0.4.0
|
||||
csscompressor==0.9.4
|
||||
rcssmin==1.0.6
|
||||
rjsmin==1.0.12
|
||||
three_two =
|
||||
flake8==2.4.0
|
||||
coverage==3.7.1
|
||||
|
@ -53,6 +59,8 @@ three_two =
|
|||
django-sekizai==0.8.2
|
||||
django-overextends==0.4.0
|
||||
csscompressor==0.9.4
|
||||
rcssmin==1.0.6
|
||||
rjsmin==1.0.12
|
||||
[tox]
|
||||
envlist =
|
||||
{py26,py27}-1.4.X,
|
||||
|
|
Loading…
Reference in New Issue