Don't mangle exported symbols

This commit is contained in:
Fábio Santos
2016-02-27 12:40:57 +00:00
committed by Richard van Velzen
parent ce84a706a3
commit 0bc4f6edb4
3 changed files with 48 additions and 10 deletions

View File

@@ -745,6 +745,16 @@ var AST_Export = DEFNODE("Export", "exported_definition exported_value is_defaul
exported_value: "[AST_Node?] An exported value", exported_value: "[AST_Node?] An exported value",
is_default: "[Boolean] Whether this is the default exported value of this module" 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); }, AST_Statement);
var AST_VarDef = DEFNODE("VarDef", "name value", { var AST_VarDef = DEFNODE("VarDef", "name value", {

View File

@@ -49,6 +49,7 @@ function SymbolDef(scope, index, orig) {
this.scope = scope; this.scope = scope;
this.references = []; this.references = [];
this.global = false; this.global = false;
this.export = false;
this.mangled_name = null; this.mangled_name = null;
this.object_destructuring_arg = false; this.object_destructuring_arg = false;
this.undeclared = false; this.undeclared = false;
@@ -61,6 +62,7 @@ SymbolDef.prototype = {
if (!options) options = {}; if (!options) options = {};
return (this.global && !options.toplevel) return (this.global && !options.toplevel)
|| this.export
|| this.object_destructuring_arg || this.object_destructuring_arg
|| this.undeclared || this.undeclared
|| (!options.eval && (this.scope.uses_eval || this.scope.uses_with)) || (!options.eval && (this.scope.uses_eval || this.scope.uses_with))
@@ -102,6 +104,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
var defun = null; var defun = null;
var nesting = 0; var nesting = 0;
var in_destructuring = null; var in_destructuring = null;
var in_export;
var tw = new TreeWalker(function(node, descend){ var tw = new TreeWalker(function(node, descend){
if (options.screw_ie8 && node instanceof AST_Catch) { if (options.screw_ie8 && node instanceof AST_Catch) {
var save_scope = scope; var save_scope = scope;
@@ -131,6 +134,11 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
labels = save_labels; labels = save_labels;
return true; // don't descend again in TreeWalker 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) { if (node instanceof AST_LabeledStatement) {
var l = node.label; var l = node.label;
if (labels.has(l.name)) { if (labels.has(l.name)) {
@@ -151,14 +159,14 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
} }
if (node instanceof AST_SymbolFunarg) { if (node instanceof AST_SymbolFunarg) {
node.object_destructuring_arg = !!in_destructuring; node.object_destructuring_arg = !!in_destructuring;
defun.def_variable(node); defun.def_variable(node, in_export);
} }
if (node instanceof AST_Label) { if (node instanceof AST_Label) {
node.thedef = node; node.thedef = node;
node.references = []; node.references = [];
} }
if (node instanceof AST_SymbolLambda) { if (node instanceof AST_SymbolLambda) {
defun.def_function(node); defun.def_function(node, in_export);
} }
else if (node instanceof AST_SymbolDefun) { else if (node instanceof AST_SymbolDefun) {
// Careful here, the scope where this should be defined is // Careful here, the scope where this should be defined is
@@ -166,22 +174,22 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
// scope when we encounter the AST_Defun node (which is // scope when we encounter the AST_Defun node (which is
// instanceof AST_Scope) but we get to the symbol a bit // instanceof AST_Scope) but we get to the symbol a bit
// later. // later.
(node.scope = defun.parent_scope).def_function(node); (node.scope = defun.parent_scope).def_function(node, in_export);
} }
else if (node instanceof AST_SymbolClass) { else if (node instanceof AST_SymbolClass) {
defun.def_variable(node); defun.def_variable(node, in_export);
} }
else if (node instanceof AST_SymbolImport) { else if (node instanceof AST_SymbolImport) {
scope.def_variable(node); scope.def_variable(node, in_export);
} }
else if (node instanceof AST_SymbolDefClass) { else if (node instanceof AST_SymbolDefClass) {
// This deals with the name of the class being available // This deals with the name of the class being available
// inside the class. // 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 else if (node instanceof AST_SymbolVar
|| node instanceof AST_SymbolConst) { || 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.constant = node instanceof AST_SymbolConst;
def.destructuring = in_destructuring; def.destructuring = in_destructuring;
def.init = tw.parent().value; def.init = tw.parent().value;
@@ -294,11 +302,11 @@ AST_Scope.DEFMETHOD("find_variable", function(name){
|| (this.parent_scope && this.parent_scope.find_variable(name)); || (this.parent_scope && this.parent_scope.find_variable(name));
}); });
AST_Scope.DEFMETHOD("def_function", function(symbol){ AST_Scope.DEFMETHOD("def_function", function(symbol, in_export){
this.functions.set(symbol.name, this.def_variable(symbol)); this.functions.set(symbol.name, this.def_variable(symbol, in_export));
}); });
AST_Scope.DEFMETHOD("def_variable", function(symbol){ AST_Scope.DEFMETHOD("def_variable", function(symbol, in_export){
var def; var def;
if (!this.variables.has(symbol.name)) { if (!this.variables.has(symbol.name)) {
def = new SymbolDef(this, this.variables.size(), symbol); def = new SymbolDef(this, this.variables.size(), symbol);
@@ -311,6 +319,10 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol){
// TODO The real fix comes with block scoping being first class in uglifyJS, // TODO The real fix comes with block scoping being first class in uglifyJS,
// enabling import definitions to behave like module-level let declarations // enabling import definitions to behave like module-level let declarations
} }
if (!this.parent_scope && in_export) {
def.global = false;
def.export = true;
}
} else { } else {
def = this.variables.get(symbol.name); def = this.variables.get(symbol.name);
def.orig.push(symbol); def.orig.push(symbol);

View File

@@ -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 // Fabio: My patches accidentally caused a crash whenever
// there's an extraneous set of parens around an object. // there's an extraneous set of parens around an object.
regression_cannot_destructure: { regression_cannot_destructure: {