Browse files

Don't mangle global scope by default.

Add -t / --mangle-toplevel command line option to enable
global scope mangling
  • Loading branch information...
1 parent 600861b commit 05ef62b416b0bdcbff84a9be56c56787dd01266d @rspivak committed Mar 15, 2012
View
15 README.rst
@@ -47,34 +47,35 @@ From the command line:
If no input file is provided STDIN is used by default.
Minified JavaScript code is printed to STDOUT.
-
Options:
- -h, --help show this help message and exit
- -m, --mangle mangle names
+ -h, --help show this help message and exit
+ -m, --mangle mangle names
+ -t, --mangle-toplevel
+ mangle top level scope (defaults to False)
$ cat test.js
- var a = function( obj ) {
+ var foo = function( obj ) {
for ( var name in obj ) {
return false;
}
return true;
};
$
$ slimit --mangle < test.js
- var a=function(a){for(var b in a)return false;return true;};
+ var foo=function(a){for(var b in a)return false;return true;};
Or using library API:
>>> from slimit import minify
>>> text = """
-... var a = function( obj ) {
+... var foo = function( obj ) {
... for ( var name in obj ) {
... return false;
... }
... return true;
... };
... """
->>> print minify(text, mangle=True)
+>>> print minify(text, mangle=True, mangle_toplevel=True)
var a=function(a){for(var b in a)return false;return true;};
View
12 docs/source/index.rst
@@ -43,19 +43,21 @@ From the command line:
Options:
- -h, --help show this help message and exit
- -m, --mangle mangle names
+ -h, --help show this help message and exit
+ -m, --mangle mangle names
+ -t, --mangle-toplevel
+ mangle top level scope (defaults to False)
$ cat test.js
- var a = function( obj ) {
+ var foo = function( obj ) {
for ( var name in obj ) {
return false;
}
return true;
};
$
$ slimit --mangle < test.js
- var a=function(a){for(var b in a)return false;return true;};
+ var foo=function(a){for(var b in a)return false;return true;};
Or using library API:
@@ -70,7 +72,7 @@ Or using library API:
... return true;
... };
... """
- >>> print minify(text, mangle=True)
+ >>> print minify(text, mangle=True, mangle_toplevel=True)
var a=function(a){for(var b in a)return false;return true;};
Iterate over, modify a JavaScript AST and pretty print it
View
10 src/slimit/mangler.py
@@ -33,13 +33,19 @@
)
-def mangle(tree):
+def mangle(tree, toplevel=False):
+ """Mangle names.
+
+ Args:
+ toplevel: defaults to False. Defines if global
+ scope should be mangled or not.
+ """
sym_table = SymbolTable()
visitor = ScopeTreeVisitor(sym_table)
visitor.visit(tree)
fill_scope_references(tree)
- mangle_scope_tree(sym_table.globals)
+ mangle_scope_tree(sym_table.globals, toplevel)
mangler = NameManglerVisitor()
mangler.visit(tree)
View
10 src/slimit/minifier.py
@@ -33,11 +33,11 @@
from slimit.visitors.minvisitor import ECMAMinifier
-def minify(text, mangle=False):
+def minify(text, mangle=False, mangle_toplevel=False):
parser = Parser()
tree = parser.parse(text)
if mangle:
- mangler.mangle(tree)
+ mangler.mangle(tree, toplevel=mangle_toplevel)
minified = ECMAMinifier().visit(tree)
return minified
@@ -52,6 +52,9 @@ def main(argv=None, inp=sys.stdin, out=sys.stdout):
parser = optparse.OptionParser(usage=usage)
parser.add_option('-m', '--mangle', action='store_true',
dest='mangle', default=False, help='mangle names')
+ parser.add_option('-t', '--mangle-toplevel', action='store_true',
+ dest='mangle_toplevel', default=False,
+ help='mangle top level scope (defaults to False)')
if argv is None:
argv = sys.argv[1:]
@@ -62,5 +65,6 @@ def main(argv=None, inp=sys.stdin, out=sys.stdout):
else:
text = inp.read()
- minified = minify(text, mangle=options.mangle)
+ minified = minify(
+ text, mangle=options.mangle, mangle_toplevel=options.mangle_toplevel)
out.write(minified)
View
15 src/slimit/tests/test_cmd.py
@@ -68,21 +68,21 @@ def tearDown(self):
def test_main_dash_m_with_input_file(self):
from slimit.minifier import main
out = StringIO.StringIO()
- main(['-m', self.path], out=out)
+ main(['-m', '-t', self.path], out=out)
self.assertEqual('var a=5;', out.getvalue())
def test_main_dash_dash_mangle_with_input_file(self):
from slimit.minifier import main
out = StringIO.StringIO()
- main(['--mangle', self.path], out=out)
+ main(['--mangle', '--mangle-toplevel', self.path], out=out)
self.assertEqual('var a=5;', out.getvalue())
def test_main_dash_m_with_mock_stdin(self):
from slimit.minifier import main
out = StringIO.StringIO()
- inp = StringIO.StringIO('var global = 5;')
+ inp = StringIO.StringIO('function foo() { var local = 5; }')
main(['-m'], inp=inp, out=out)
- self.assertEqual('var a=5;', out.getvalue())
+ self.assertEqual('function foo(){var a=5;}', out.getvalue())
def test_main_stdin_stdout(self):
# slimit.minifier should be deleted from sys.modules in order
@@ -93,16 +93,17 @@ def test_main_stdin_stdout(self):
except KeyError:
pass
- with redirected_input_output(input='var global = 5;') as out:
+ with redirected_input_output(
+ input='function foo() { var local = 5; }') as out:
from slimit.minifier import main
main(['-m'])
- self.assertEqual('var a=5;', out.getvalue())
+ self.assertEqual('function foo(){var a=5;}', out.getvalue())
def test_main_sys_argv(self):
out = StringIO.StringIO()
inp = StringIO.StringIO('var global = 5;')
- with redirected_sys_argv(['slimit', '-m']):
+ with redirected_sys_argv(['slimit', '-m', '-t']):
from slimit.minifier import main
main(inp=inp, out=out)
View
2 src/slimit/tests/test_mangler.py
@@ -143,7 +143,7 @@ def make_test_function(input, expected):
def test_func(self):
parser = Parser()
tree = parser.parse(input)
- mangle(tree)
+ mangle(tree, toplevel=True)
self.assertMultiLineEqual(
textwrap.dedent(tree.to_ecma()).strip(),
textwrap.dedent(expected).strip()
View
11 src/slimit/visitors/scopevisitor.py
@@ -137,9 +137,16 @@ def _fill_scope_refs(name, scope):
scope.refs[name] = orig_scope
-def mangle_scope_tree(root):
- """Walk over a scope tree and mangle symbol names."""
+def mangle_scope_tree(root, toplevel):
+ """Walk over a scope tree and mangle symbol names.
+
+ Args:
+ toplevel: Defines if global scope should be mangled or not.
+ """
def mangle(scope):
+ # don't mangle global scope if not specified otherwise
+ if scope.get_enclosing_scope() is None and not toplevel:
+ return
for name in scope.symbols:
mangled_name = scope.get_next_mangled_name()
scope.mangled[name] = mangled_name

0 comments on commit 05ef62b

Please sign in to comment.