From 86b5248837d3b4f2bfa14da6537e349b3306df26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Santos?= Date: Sat, 27 Feb 2016 12:01:16 +0000 Subject: [PATCH] Mangling externally imported names by using aliasing --- lib/ast.js | 11 +++++++++++ lib/output.js | 8 ++++++-- lib/parse.js | 8 ++++++++ lib/scope.js | 9 +++++++++ test/compress/harmony.js | 10 ++++++++++ 5 files changed, 44 insertions(+), 2 deletions(-) diff --git a/lib/ast.js b/lib/ast.js index 768bfc78..6a814e35 100644 --- a/lib/ast.js +++ b/lib/ast.js @@ -707,6 +707,12 @@ var AST_NameImport = DEFNODE("NameImport", "foreign_name name", { $propdoc: { foreign_name: "[AST_SymbolImportForeign] The name being imported (as specified in the module)", name: "[AST_SymbolImport] The name as it becomes available to this module." + }, + _walk: function (visitor) { + return visitor._visit(this, function() { + this.foreign_name._walk(visitor); + this.name._walk(visitor); + }); } }) @@ -722,6 +728,11 @@ var AST_Import = DEFNODE("Import", "imported_name imported_names module_name", { if (this.imported_name) { this.imported_name._walk(visitor); } + if (this.imported_names) { + this.imported_names.forEach(function (name_import) { + name_import._walk(visitor); + }); + } this.module_name._walk(visitor); }); } diff --git a/lib/output.js b/lib/output.js index a9c78bbf..e755ec04 100644 --- a/lib/output.js +++ b/lib/output.js @@ -1070,8 +1070,12 @@ function OutputStream(options) { }); DEFPRINT(AST_NameImport, function(self, output) { - if (self.foreign_name) { - self.foreign_name.print(output); + var definition = self.name.definition(); + var names_are_different = + (definition && definition.mangled_name || self.name.name) !== + self.foreign_name.name; + if (names_are_different) { + output.print(self.foreign_name.name); output.space(); output.print("as"); output.space(); diff --git a/lib/parse.js b/lib/parse.js index fd51eda2..134b3f19 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -1667,6 +1667,14 @@ function parse($TEXT, options) { } name = as_symbol(AST_SymbolImport); + if (foreign_name === undefined) { + foreign_name = new AST_SymbolImportForeign({ + name: name.name, + start: name.start, + end: name.end, + }); + } + return new AST_NameImport({ start: start, foreign_name: foreign_name, diff --git a/lib/scope.js b/lib/scope.js index 371afb2b..23f70ad1 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -171,6 +171,9 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){ else if (node instanceof AST_SymbolClass) { defun.def_variable(node); } + else if (node instanceof AST_SymbolImport) { + scope.def_variable(node); + } else if (node instanceof AST_SymbolDefClass) { // This deals with the name of the class being available // inside the class. @@ -302,6 +305,12 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol){ this.variables.set(symbol.name, def); def.object_destructuring_arg = symbol.object_destructuring_arg; def.global = !this.parent_scope; + if (symbol instanceof AST_SymbolImport) { + // Imports are not global + def.global = false; + // TODO The real fix comes with block scoping being first class in uglifyJS, + // enabling import definitions to behave like module-level let declarations + } } else { def = this.variables.get(symbol.name); def.orig.push(symbol); diff --git a/test/compress/harmony.js b/test/compress/harmony.js index 59c6238a..5ef1416e 100644 --- a/test/compress/harmony.js +++ b/test/compress/harmony.js @@ -320,11 +320,21 @@ import_statement_mangling: { mangle = { }; input: { import Foo from "foo"; + import Bar, {Food} from "lel"; + import {What as Whatever} from "lel"; Foo(); + Bar(); + Food(); + Whatever(); } expect: { import a from "foo"; + import b, {Food as c} from "lel"; + import {What as d} from "lel"; a(); + b(); + c(); + d(); } }