From a3f094013db0597bb46acbf9bd3c31ea17bf48c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Santos?= Date: Sat, 27 Feb 2016 12:40:57 +0000 Subject: [PATCH] Don't mangle exported symbols --- lib/ast.js | 10 ++++++++++ lib/scope.js | 28 ++++++++++++++++++++-------- test/compress/harmony.js | 16 ++++++++++++++++ 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/lib/ast.js b/lib/ast.js index 2acf5e6b..71459770 100644 --- a/lib/ast.js +++ b/lib/ast.js @@ -745,6 +745,16 @@ var AST_Export = DEFNODE("Export", "exported_definition exported_value is_defaul exported_value: "[AST_Node?] An exported value", is_default: "[Boolean] Whether this is the default exported value of this module" }, + _walk: function (visitor) { + visitor._visit(this, function () { + if (this.exported_definition) { + this.exported_definition._walk(visitor); + } + if (this.exported_value) { + this.exported_value._walk(visitor); + } + }); + } }, AST_Statement); var AST_VarDef = DEFNODE("VarDef", "name value", { diff --git a/lib/scope.js b/lib/scope.js index 789865af..5de7aa23 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -49,6 +49,7 @@ function SymbolDef(scope, index, orig) { this.scope = scope; this.references = []; this.global = false; + this.export = false; this.mangled_name = null; this.object_destructuring_arg = false; this.undeclared = false; @@ -61,6 +62,7 @@ SymbolDef.prototype = { if (!options) options = {}; return (this.global && !options.toplevel) + || this.export || this.object_destructuring_arg || this.undeclared || (!options.eval && (this.scope.uses_eval || this.scope.uses_with)) @@ -103,6 +105,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){ var last_var_had_const_pragma = false; var nesting = 0; var in_destructuring = null; + var in_export; var tw = new TreeWalker(function(node, descend){ if (options.screw_ie8 && node instanceof AST_Catch) { var save_scope = scope; @@ -132,6 +135,11 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){ labels = save_labels; return true; // don't descend again in TreeWalker } + if (node instanceof AST_Export) { + in_export = true; + descend(); + in_export = false; + } if (node instanceof AST_LabeledStatement) { var l = node.label; if (labels.has(l.name)) { @@ -156,10 +164,10 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){ } if (node instanceof AST_SymbolFunarg) { node.object_destructuring_arg = !!in_destructuring; - defun.def_variable(node); + defun.def_variable(node, in_export); } if (node instanceof AST_SymbolLambda) { - defun.def_function(node); + defun.def_function(node, in_export); } else if (node instanceof AST_SymbolDefun) { // Careful here, the scope where this should be defined is @@ -167,25 +175,25 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){ // scope when we encounter the AST_Defun node (which is // instanceof AST_Scope) but we get to the symbol a bit // later. - (node.scope = defun.parent_scope).def_function(node); + (node.scope = defun.parent_scope).def_function(node, in_export); } else if (node instanceof AST_Var) { last_var_had_const_pragma = node.has_const_pragma(); } else if (node instanceof AST_SymbolClass) { - defun.def_variable(node); + defun.def_variable(node, in_export); } else if (node instanceof AST_SymbolImport) { - scope.def_variable(node); + scope.def_variable(node, in_export); } else if (node instanceof AST_SymbolDefClass) { // This deals with the name of the class being available // inside the class. - (node.scope = defun.parent_scope).def_function(node); + (node.scope = defun.parent_scope).def_function(node, in_export); } else if (node instanceof AST_SymbolVar || node instanceof AST_SymbolConst) { - var def = defun.def_variable(node); + var def = defun.def_variable(node, in_export); def.constant = node instanceof AST_SymbolConst; def.destructuring = in_destructuring; def.init = tw.parent().value; @@ -317,7 +325,7 @@ AST_Scope.DEFMETHOD("def_function", function(symbol){ this.functions.set(symbol.name, this.def_variable(symbol)); }); -AST_Scope.DEFMETHOD("def_variable", function(symbol){ +AST_Scope.DEFMETHOD("def_variable", function(symbol, in_export){ var def; if (!this.variables.has(symbol.name)) { def = new SymbolDef(this, this.variables.size(), symbol); @@ -330,6 +338,10 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol){ // TODO The real fix comes with block scoping being first class in uglifyJS, // enabling import definitions to behave like module-level let declarations } + if (!this.parent_scope && in_export) { + def.global = false; + def.export = true; + } } else { def = this.variables.get(symbol.name); def.orig.push(symbol); diff --git a/test/compress/harmony.js b/test/compress/harmony.js index d27d903b..fec3a835 100644 --- a/test/compress/harmony.js +++ b/test/compress/harmony.js @@ -350,6 +350,22 @@ import_statement_mangling: { } } +export_statement_mangling: { + mangle = { }; + input: { + export var foo = 6; + export function bar() { } + export class Baz { } + bar(foo, Baz) + } + expect: { + export var foo = 6; + export function bar() { } + export class Baz { } + bar(foo, Baz) + } +} + // Fabio: My patches accidentally caused a crash whenever // there's an extraneous set of parens around an object. regression_cannot_destructure: {