support string namespace in import & export (#5570)

This commit is contained in:
Alex Lam S.L
2022-07-19 22:55:38 +01:00
committed by GitHub
parent f0120e90b6
commit d67daa8314
9 changed files with 295 additions and 134 deletions

View File

@@ -1366,34 +1366,29 @@ var AST_ExportDefault = DEFNODE("ExportDefault", "body", {
}, },
}, AST_Statement); }, AST_Statement);
var AST_ExportForeign = DEFNODE("ExportForeign", "aliases keys path quote", { var AST_ExportForeign = DEFNODE("ExportForeign", "aliases keys path", {
$documentation: "An `export ... from '...'` statement", $documentation: "An `export ... from '...'` statement",
$propdoc: { $propdoc: {
aliases: "[string*] array of aliases to export", aliases: "[AST_String*] array of aliases to export",
keys: "[string*] array of keys to import", keys: "[AST_String*] array of keys to import",
path: "[string] the path to import module", path: "[AST_String] the path to import module",
quote: "[string?] the original quote character",
}, },
_equals: function(node) { _equals: function(node) {
return this.path == node.path return this.path.equals(node.path)
&& list_equals(this.aliases, node.aliases) && all_equals(this.aliases, node.aliases)
&& list_equals(this.keys, node.keys); && all_equals(this.keys, node.keys);
}, },
_validate: function() { _validate: function() {
if (this.aliases.length != this.keys.length) { if (this.aliases.length != this.keys.length) {
throw new Error("aliases:key length mismatch: " + this.aliases.length + " != " + this.keys.length); throw new Error("aliases:key length mismatch: " + this.aliases.length + " != " + this.keys.length);
} }
this.aliases.forEach(function(name) { this.aliases.forEach(function(name) {
if (typeof name != "string") throw new Error("aliases must contain string"); if (!(name instanceof AST_String)) throw new Error("aliases must contain AST_String");
}); });
this.keys.forEach(function(name) { this.keys.forEach(function(name) {
if (typeof name != "string") throw new Error("keys must contain string"); if (!(name instanceof AST_String)) throw new Error("keys must contain AST_String");
}); });
if (typeof this.path != "string") throw new Error("path must be string"); if (!(this.path instanceof AST_String)) throw new Error("path must be AST_String");
if (this.quote != null) {
if (typeof this.quote != "string") throw new Error("quote must be string");
if (!/^["']$/.test(this.quote)) throw new Error("invalid quote: " + this.quote);
}
}, },
}, AST_Statement); }, AST_Statement);
@@ -1420,17 +1415,16 @@ var AST_ExportReferences = DEFNODE("ExportReferences", "properties", {
}, },
}, AST_Statement); }, AST_Statement);
var AST_Import = DEFNODE("Import", "all default path properties quote", { var AST_Import = DEFNODE("Import", "all default path properties", {
$documentation: "An `import` statement", $documentation: "An `import` statement",
$propdoc: { $propdoc: {
all: "[AST_SymbolImport?] the imported namespace, or null if not specified", all: "[AST_SymbolImport?] the imported namespace, or null if not specified",
default: "[AST_SymbolImport?] the alias for default `export`, or null if not specified", default: "[AST_SymbolImport?] the alias for default `export`, or null if not specified",
path: "[string] the path to import module", path: "[AST_String] the path to import module",
properties: "[(AST_SymbolImport*)?] array of aliases, or null if not specified", properties: "[(AST_SymbolImport*)?] array of aliases, or null if not specified",
quote: "[string?] the original quote character",
}, },
_equals: function(node) { _equals: function(node) {
return this.path == node.path return this.path.equals(node.path)
&& prop_equals(this.all, node.all) && prop_equals(this.all, node.all)
&& prop_equals(this.default, node.default) && prop_equals(this.default, node.default)
&& !this.properties == !node.properties && !this.properties == !node.properties
@@ -1453,16 +1447,12 @@ var AST_Import = DEFNODE("Import", "all default path properties quote", {
} }
if (this.default != null) { if (this.default != null) {
if (!(this.default instanceof AST_SymbolImport)) throw new Error("default must be AST_SymbolImport"); if (!(this.default instanceof AST_SymbolImport)) throw new Error("default must be AST_SymbolImport");
if (this.default.key !== "") throw new Error("invalid default key: " + this.default.key); if (this.default.key.value !== "") throw new Error("invalid default key: " + this.default.key.value);
} }
if (typeof this.path != "string") throw new Error("path must be string"); if (!(this.path instanceof AST_String)) throw new Error("path must be AST_String");
if (this.properties != null) this.properties.forEach(function(node) { if (this.properties != null) this.properties.forEach(function(node) {
if (!(node instanceof AST_SymbolImport)) throw new Error("properties must contain AST_SymbolImport"); if (!(node instanceof AST_SymbolImport)) throw new Error("properties must contain AST_SymbolImport");
}); });
if (this.quote != null) {
if (typeof this.quote != "string") throw new Error("quote must be string");
if (!/^["']$/.test(this.quote)) throw new Error("invalid quote: " + this.quote);
}
}, },
}, AST_Statement); }, AST_Statement);
@@ -2005,14 +1995,14 @@ var AST_SymbolConst = DEFNODE("SymbolConst", null, {
var AST_SymbolImport = DEFNODE("SymbolImport", "key", { var AST_SymbolImport = DEFNODE("SymbolImport", "key", {
$documentation: "Symbol defined by an `import` statement", $documentation: "Symbol defined by an `import` statement",
$propdoc: { $propdoc: {
key: "[string] the original `export` name", key: "[AST_String] the original `export` name",
}, },
_equals: function(node) { _equals: function(node) {
return this.name == node.name return this.name == node.name
&& this.key == node.key; && this.key.equals(node.key);
}, },
_validate: function() { _validate: function() {
if (typeof this.key != "string") throw new Error("key must be string"); if (!(this.key instanceof AST_String)) throw new Error("key must be AST_String");
}, },
}, AST_SymbolConst); }, AST_SymbolConst);
@@ -2066,14 +2056,14 @@ var AST_SymbolRef = DEFNODE("SymbolRef", "fixed in_arg redef", {
var AST_SymbolExport = DEFNODE("SymbolExport", "alias", { var AST_SymbolExport = DEFNODE("SymbolExport", "alias", {
$documentation: "Reference in an `export` statement", $documentation: "Reference in an `export` statement",
$propdoc: { $propdoc: {
alias: "[string] the `export` alias", alias: "[AST_String] the `export` alias",
}, },
_equals: function(node) { _equals: function(node) {
return this.name == node.name return this.name == node.name
&& this.alias == node.alias; && this.alias.equals(node.alias);
}, },
_validate: function() { _validate: function() {
if (typeof this.alias != "string") throw new Error("alias must be string"); if (!(this.alias instanceof AST_String)) throw new Error("alias must be AST_String");
}, },
}, AST_SymbolRef); }, AST_SymbolRef);

View File

@@ -294,7 +294,7 @@ Compressor.prototype.compress = function(node) {
function export_symbol(sym) { function export_symbol(sym) {
if (!(sym instanceof AST_SymbolDeclaration)) return; if (!(sym instanceof AST_SymbolDeclaration)) return;
var node = make_node(AST_SymbolExport, sym, sym); var node = make_node(AST_SymbolExport, sym, sym);
node.alias = node.name; node.alias = make_node(AST_String, node, { value: node.name });
props.push(node); props.push(node);
} }
}); });

View File

@@ -316,13 +316,22 @@
}); });
}, },
ExportAllDeclaration: function(M) { ExportAllDeclaration: function(M) {
var alias = M.exported ? read_name(M.exported) : "*"; var start = my_start_token(M);
var end = my_end_token(M);
return new AST_ExportForeign({ return new AST_ExportForeign({
start: my_start_token(M), start: start,
end: my_end_token(M), end: end,
aliases: [ alias ], aliases: [ M.exported ? from_moz_alias(M.exported) : new AST_String({
keys: [ "*" ], start: start,
path: M.source.value, value: "*",
end: end,
}) ],
keys: [ new AST_String({
start: start,
value: "*",
end: end,
}) ],
path: from_moz(M.source),
}); });
}, },
ExportDefaultDeclaration: function(M) { ExportDefaultDeclaration: function(M) {
@@ -359,15 +368,15 @@
if (M.source) { if (M.source) {
var aliases = [], keys = []; var aliases = [], keys = [];
M.specifiers.forEach(function(prop) { M.specifiers.forEach(function(prop) {
aliases.push(read_name(prop.exported)); aliases.push(from_moz_alias(prop.exported));
keys.push(read_name(prop.local)); keys.push(from_moz_alias(prop.local));
}); });
return new AST_ExportForeign({ return new AST_ExportForeign({
start: my_start_token(M), start: my_start_token(M),
end: my_end_token(M), end: my_end_token(M),
aliases: aliases, aliases: aliases,
keys: keys, keys: keys,
path: M.source.value, path: from_moz(M.source),
}); });
} }
return new AST_ExportReferences({ return new AST_ExportReferences({
@@ -375,38 +384,48 @@
end: my_end_token(M), end: my_end_token(M),
properties: M.specifiers.map(function(prop) { properties: M.specifiers.map(function(prop) {
var sym = new AST_SymbolExport(from_moz(prop.local)); var sym = new AST_SymbolExport(from_moz(prop.local));
sym.alias = read_name(prop.exported); sym.alias = from_moz_alias(prop.exported);
return sym; return sym;
}), }),
}); });
}, },
ImportDeclaration: function(M) { ImportDeclaration: function(M) {
var start = my_start_token(M);
var end = my_end_token(M);
var all = null, def = null, props = null; var all = null, def = null, props = null;
M.specifiers.forEach(function(prop) { M.specifiers.forEach(function(prop) {
var sym = new AST_SymbolImport(from_moz(prop.local)); var sym = new AST_SymbolImport(from_moz(prop.local));
switch (prop.type) { switch (prop.type) {
case "ImportDefaultSpecifier": case "ImportDefaultSpecifier":
def = sym; def = sym;
def.key = ""; def.key = new AST_String({
start: start,
value: "",
end: end,
});
break; break;
case "ImportNamespaceSpecifier": case "ImportNamespaceSpecifier":
all = sym; all = sym;
all.key = "*"; all.key = new AST_String({
start: start,
value: "*",
end: end,
});
break; break;
default: default:
sym.key = prop.imported.name || syn.name; sym.key = from_moz_alias(prop.imported);
if (!props) props = []; if (!props) props = [];
props.push(sym); props.push(sym);
break; break;
} }
}); });
return new AST_Import({ return new AST_Import({
start: my_start_token(M), start: start,
end: my_end_token(M), end: end,
all: all, all: all,
default: def, default: def,
properties: props, properties: props,
path: M.source.value, path: from_moz(M.source),
}); });
}, },
ImportExpression: function(M) { ImportExpression: function(M) {
@@ -797,38 +816,26 @@
}); });
def_to_moz(AST_ExportForeign, function To_Moz_ExportAllDeclaration_ExportNamedDeclaration(M) { def_to_moz(AST_ExportForeign, function To_Moz_ExportAllDeclaration_ExportNamedDeclaration(M) {
if (M.keys[0] == "*") return { if (M.keys[0].value == "*") return {
type: "ExportAllDeclaration", type: "ExportAllDeclaration",
exported: M.aliases[0] == "*" ? null : { exported: M.aliases[0].value == "*" ? null : to_moz_alias(M.aliases[0]),
type: "Identifier", source: to_moz(M.path),
name: M.aliases[0],
},
source: {
type: "Literal",
value: M.path,
},
}; };
var specifiers = []; var specifiers = [];
for (var i = 0; i < M.aliases.length; i++) { for (var i = 0; i < M.aliases.length; i++) {
specifiers.push({ specifiers.push(set_moz_loc({
start: M.keys[i].start,
end: M.aliases[i].end,
}, {
type: "ExportSpecifier", type: "ExportSpecifier",
exported: { local: to_moz_alias(M.keys[i]),
type: "Identifier", exported: to_moz_alias(M.aliases[i]),
name: M.aliases[i], }));
},
local: {
type: "Identifier",
name: M.keys[i],
},
});
} }
return { return {
type: "ExportNamedDeclaration", type: "ExportNamedDeclaration",
specifiers: specifiers, specifiers: specifiers,
source: { source: to_moz(M.path),
type: "Literal",
value: M.path,
},
}; };
}); });
@@ -836,44 +843,41 @@
return { return {
type: "ExportNamedDeclaration", type: "ExportNamedDeclaration",
specifiers: M.properties.map(function(prop) { specifiers: M.properties.map(function(prop) {
return { return set_moz_loc({
start: prop.start,
end: prop.alias.end,
}, {
type: "ExportSpecifier", type: "ExportSpecifier",
local: to_moz(prop), local: to_moz(prop),
exported: { exported: to_moz_alias(prop.alias),
type: "Identifier", });
name: prop.alias,
},
};
}), }),
}; };
}); });
def_to_moz(AST_Import, function To_Moz_ImportDeclaration(M) { def_to_moz(AST_Import, function To_Moz_ImportDeclaration(M) {
var specifiers = M.properties ? M.properties.map(function(prop) { var specifiers = M.properties ? M.properties.map(function(prop) {
return { return set_moz_loc({
start: prop.key.start,
end: prop.end,
}, {
type: "ImportSpecifier", type: "ImportSpecifier",
local: to_moz(prop), local: to_moz(prop),
imported: { imported: to_moz_alias(prop.key),
type: "Identifier", });
name: prop.key,
},
};
}) : []; }) : [];
if (M.all) specifiers.unshift({ if (M.all) specifiers.unshift(set_moz_loc(M.all, {
type: "ImportNamespaceSpecifier", type: "ImportNamespaceSpecifier",
local: to_moz(M.all), local: to_moz(M.all),
}); }));
if (M.default) specifiers.unshift({ if (M.default) specifiers.unshift(set_moz_loc(M.default, {
type: "ImportDefaultSpecifier", type: "ImportDefaultSpecifier",
local: to_moz(M.default), local: to_moz(M.default),
}); }));
return { return {
type: "ImportDeclaration", type: "ImportDeclaration",
specifiers: specifiers, specifiers: specifiers,
source: { source: to_moz(M.path),
type: "Literal",
value: M.path,
},
}; };
}); });
@@ -1220,6 +1224,14 @@
return node; return node;
} }
function from_moz_alias(moz) {
return new AST_String({
start: my_start_token(moz),
value: read_name(moz),
end: my_end_token(moz),
});
}
AST_Node.from_mozilla_ast = function(node) { AST_Node.from_mozilla_ast = function(node) {
var save_stack = FROM_MOZ_STACK; var save_stack = FROM_MOZ_STACK;
FROM_MOZ_STACK = []; FROM_MOZ_STACK = [];
@@ -1271,6 +1283,13 @@
return node != null ? node.to_mozilla_ast() : null; return node != null ? node.to_mozilla_ast() : null;
} }
function to_moz_alias(alias) {
return is_identifier_string(alias.value) ? set_moz_loc(alias, {
type: "Identifier",
name: alias.value,
}) : to_moz(alias);
}
function to_moz_block(node) { function to_moz_block(node) {
return { return {
type: "BlockStatement", type: "BlockStatement",

View File

@@ -1061,6 +1061,14 @@ function OutputStream(options) {
} }
output.semicolon(); output.semicolon();
}); });
function print_alias(alias, output) {
var value = alias.value;
if (value == "*" || is_identifier_string(value)) {
output.print_name(value);
} else {
output.print_string(value, alias.quote);
}
}
DEFPRINT(AST_ExportForeign, function(output) { DEFPRINT(AST_ExportForeign, function(output) {
var self = this; var self = this;
output.print("export"); output.print("export");
@@ -1068,7 +1076,7 @@ function OutputStream(options) {
var len = self.keys.length; var len = self.keys.length;
if (len == 0) { if (len == 0) {
print_braced_empty(self, output); print_braced_empty(self, output);
} else if (self.keys[0] == "*") { } else if (self.keys[0].value == "*") {
print_entry(0); print_entry(0);
} else output.with_block(function() { } else output.with_block(function() {
output.indent(); output.indent();
@@ -1084,18 +1092,18 @@ function OutputStream(options) {
output.space(); output.space();
output.print("from"); output.print("from");
output.space(); output.space();
output.print_string(self.path, self.quote); self.path.print(output);
output.semicolon(); output.semicolon();
function print_entry(index) { function print_entry(index) {
var alias = self.aliases[index]; var alias = self.aliases[index];
var key = self.keys[index]; var key = self.keys[index];
output.print_name(key); print_alias(key, output);
if (alias != key) { if (alias.value != key.value) {
output.space(); output.space();
output.print("as"); output.print("as");
output.space(); output.space();
output.print_name(alias); print_alias(alias, output);
} }
} }
}); });
@@ -1124,7 +1132,7 @@ function OutputStream(options) {
output.print("from"); output.print("from");
output.space(); output.space();
} }
output.print_string(self.path, self.quote); self.path.print(output);
output.semicolon(); output.semicolon();
}); });
@@ -1734,19 +1742,19 @@ function OutputStream(options) {
var name = get_symbol_name(self); var name = get_symbol_name(self);
output.print_name(name); output.print_name(name);
var alias = self.alias; var alias = self.alias;
if (alias != name) { if (alias.value != name) {
output.space(); output.space();
output.print("as"); output.print("as");
output.space(); output.space();
output.print_name(alias); print_alias(alias, output);
} }
}); });
DEFPRINT(AST_SymbolImport, function(output) { DEFPRINT(AST_SymbolImport, function(output) {
var self = this; var self = this;
var name = get_symbol_name(self); var name = get_symbol_name(self);
var key = self.key; var key = self.key;
if (key && key != name) { if (key.value && key.value != name) {
output.print_name(key); print_alias(key, output);
output.space(); output.space();
output.print("as"); output.print("as");
output.space(); output.space();

View File

@@ -1442,28 +1442,41 @@ function parse($TEXT, options) {
} }
function is_alias() { function is_alias() {
return is("name") || is_identifier_string(S.token.value); return is("name") || is("string") || is_identifier_string(S.token.value);
}
function make_string(token) {
return new AST_String({
start: token,
quote: token.quote,
value: token.value,
end: token,
});
}
function as_path() {
var path = S.token;
expect_token("string");
semicolon();
return make_string(path);
} }
function export_() { function export_() {
if (is("operator", "*")) { if (is("operator", "*")) {
var key = S.token;
var alias = key;
next(); next();
var alias = "*";
if (is("name", "as")) { if (is("name", "as")) {
next(); next();
if (!is_alias()) expect_token("name"); if (!is_alias()) expect_token("name");
alias = S.token.value; alias = S.token;
next(); next();
} }
expect_token("name", "from"); expect_token("name", "from");
var path = S.token;
expect_token("string");
semicolon();
return new AST_ExportForeign({ return new AST_ExportForeign({
aliases: [ alias ], aliases: [ make_string(alias) ],
keys: [ "*" ], keys: [ make_string(key) ],
path: path.value, path: as_path(),
quote: path.quote,
}); });
} }
if (is("punc", "{")) { if (is("punc", "{")) {
@@ -1477,26 +1490,20 @@ function parse($TEXT, options) {
if (is("name", "as")) { if (is("name", "as")) {
next(); next();
if (!is_alias()) expect_token("name"); if (!is_alias()) expect_token("name");
aliases.push(S.token.value); aliases.push(S.token);
next(); next();
} else { } else {
aliases.push(key.value); aliases.push(key);
} }
if (!is("punc", "}")) expect(","); if (!is("punc", "}")) expect(",");
} }
expect("}"); expect("}");
if (is("name", "from")) { if (is("name", "from")) {
next(); next();
var path = S.token;
expect_token("string");
semicolon();
return new AST_ExportForeign({ return new AST_ExportForeign({
aliases: aliases, aliases: aliases.map(make_string),
keys: keys.map(function(token) { keys: keys.map(make_string),
return token.value; path: as_path(),
}),
path: path.value,
quote: path.quote,
}); });
} }
semicolon(); semicolon();
@@ -1504,7 +1511,7 @@ function parse($TEXT, options) {
properties: keys.map(function(token, index) { properties: keys.map(function(token, index) {
if (!is_token(token, "name")) token_error(token, "Name expected"); if (!is_token(token, "name")) token_error(token, "Name expected");
var sym = _make_symbol(AST_SymbolExport, token); var sym = _make_symbol(AST_SymbolExport, token);
sym.alias = aliases[index]; sym.alias = make_string(aliases[index]);
return sym; return sym;
}), }),
}); });
@@ -1594,26 +1601,42 @@ function parse($TEXT, options) {
var all = null; var all = null;
var def = as_symbol(AST_SymbolImport, true); var def = as_symbol(AST_SymbolImport, true);
var props = null; var props = null;
if (def ? (def.key = "", is("punc", ",") && next()) : !is("string")) { var cont;
if (def) {
def.key = new AST_String({
start: def.start,
value: "",
end: def.end,
});
if (cont = is("punc", ",")) next();
} else {
cont = !is("string");
}
if (cont) {
if (is("operator", "*")) { if (is("operator", "*")) {
var key = S.token;
next(); next();
expect_token("name", "as"); expect_token("name", "as");
all = as_symbol(AST_SymbolImport); all = as_symbol(AST_SymbolImport);
all.key = "*"; all.key = make_string(key);
} else { } else {
expect("{"); expect("{");
props = []; props = [];
while (is_alias()) { while (is_alias()) {
var alias; var alias;
if (is_token(peek(), "name", "as")) { if (is_token(peek(), "name", "as")) {
var key = S.token.value; var key = S.token;
next(); next();
next(); next();
alias = as_symbol(AST_SymbolImport); alias = as_symbol(AST_SymbolImport);
alias.key = key; alias.key = make_string(key);
} else { } else {
alias = as_symbol(AST_SymbolImport); alias = as_symbol(AST_SymbolImport);
alias.key = alias.name; alias.key = new AST_String({
start: alias.start,
value: alias.name,
end: alias.end,
});
} }
props.push(alias); props.push(alias);
if (!is("punc", "}")) expect(","); if (!is("punc", "}")) expect(",");
@@ -1622,15 +1645,11 @@ function parse($TEXT, options) {
} }
} }
if (all || def || props) expect_token("name", "from"); if (all || def || props) expect_token("name", "from");
var path = S.token;
expect_token("string");
semicolon();
return new AST_Import({ return new AST_Import({
all: all, all: all,
default: def, default: def,
path: path.value, path: as_path(),
properties: props, properties: props,
quote: path.quote,
}); });
} }
@@ -1808,7 +1827,7 @@ function parse($TEXT, options) {
ret = new AST_BigInt({ value: value }); ret = new AST_BigInt({ value: value });
break; break;
case "string": case "string":
ret = new AST_String({ value : value, quote : tok.quote }); ret = new AST_String({ value: value, quote: tok.quote });
break; break;
case "regexp": case "regexp":
ret = new AST_RegExp({ value: value }); ret = new AST_RegExp({ value: value });

View File

@@ -109,6 +109,17 @@ foreign: {
expect_exact: 'export*from"foo";export{}from"bar";export*as a from"baz";export{default}from"moo";export{b,c as case,default as delete,d}from"moz";' expect_exact: 'export*from"foo";export{}from"bar";export*as a from"baz";export{default}from"moo";export{b,c as case,default as delete,d}from"moz";'
} }
non_identifiers: {
beautify = {
quote_style: 3,
}
input: {
export * as "42" from 'foo';
export { '42', "delete" as 'foo' } from "bar";
}
expect_exact: "export*as\"42\"from'foo';export{'42',delete as foo}from\"bar\";"
}
same_quotes: { same_quotes: {
beautify = { beautify = {
beautify: true, beautify: true,

View File

@@ -40,6 +40,17 @@ default_keys: {
expect_exact: 'import foo,{bar}from"baz";' expect_exact: 'import foo,{bar}from"baz";'
} }
non_identifiers: {
beautify = {
quote_style: 3,
}
input: {
import { '42' as foo } from "bar";
import { "foo" as bar } from 'baz';
}
expect_exact: "import{'42'as foo}from\"bar\";import{foo as bar}from'baz';"
}
dynamic: { dynamic: {
input: { input: {
(async a => await import(a))("foo").then(bar); (async a => await import(a))("foo").then(bar);

View File

@@ -1,3 +1,4 @@
var acorn = require("acorn");
var assert = require("assert"); var assert = require("assert");
var UglifyJS = require("../node"); var UglifyJS = require("../node");
@@ -25,6 +26,7 @@ describe("export", function() {
"export { * };", "export { * };",
"export { * as A };", "export { * as A };",
"export { 42 as A };", "export { 42 as A };",
"export { 'A' as B };",
"export { A as B-C };", "export { A as B-C };",
"export { default as A };", "export { default as A };",
].forEach(function(code) { ].forEach(function(code) {
@@ -51,8 +53,11 @@ describe("export", function() {
it("Should reject invalid `export ... from ...` statement syntax", function() { it("Should reject invalid `export ... from ...` statement syntax", function() {
[ [
"export from 'path';", "export from 'path';",
"export A from 'path';",
"export * from `path`;", "export * from `path`;",
"export 'A' from 'path';",
"export A as B from 'path';", "export A as B from 'path';",
"export 'A' as B from 'path';",
"export default from 'path';", "export default from 'path';",
"export { A }, B from 'path';", "export { A }, B from 'path';",
"export * as A, B from 'path';", "export * as A, B from 'path';",
@@ -128,4 +133,49 @@ describe("export", function() {
}); });
}); });
}); });
it("Should interoperate with ESTree correctly", function() {
[
"export var A = 42;",
"export default (class A {});",
"var A; export { A as '42' };",
"export { '42' } from 'path';",
"export * as '42' from 'path';",
].forEach(function(code) {
var ast = UglifyJS.parse(code);
try {
var spidermonkey = ast.to_mozilla_ast();
} catch (ex) {
assert.fail("[to_mozilla_ast] " + ex.stack);
}
try {
var ast2 = UglifyJS.AST_Node.from_mozilla_ast(spidermonkey);
} catch (ex) {
assert.fail("[from_mozilla_ast] " + ex.stack);
}
assert.strictEqual(ast2.print_to_string(), ast.print_to_string(), [
"spidermonkey:",
ast.print_to_string(),
ast2.print_to_string(),
].join("\n"));
try {
var acorn_est = acorn.parse(code, {
ecmaVersion: "latest",
locations: true,
sourceType: "module",
});
} catch (ex) {
assert.fail("[acorn.parse] " + ex.stack);
}
try {
var ast3 = UglifyJS.AST_Node.from_mozilla_ast(acorn_est);
} catch (ex) {
assert.fail("[from_acorn] " + ex.stack);
}
assert.strictEqual(ast3.print_to_string(), ast.print_to_string(), [
"acorn:",
ast.print_to_string(),
ast3.print_to_string(),
].join("\n"));
});
});
}); });

View File

@@ -1,3 +1,4 @@
var acorn = require("acorn");
var assert = require("assert"); var assert = require("assert");
var UglifyJS = require("../node"); var UglifyJS = require("../node");
@@ -12,14 +13,21 @@ describe("import", function() {
"import from 'path';", "import from 'path';",
"if (0) import 'path';", "if (0) import 'path';",
"import * from 'path';", "import * from 'path';",
"import 'A' from 'path';",
"import A-B from 'path';",
"import A as B from 'path';", "import A as B from 'path';",
"import { A }, B from 'path';", "import { A }, B from 'path';",
"import * as 'A' from 'path';",
"import * as A-B from 'path';",
"import * as A, B from 'path';", "import * as A, B from 'path';",
"import * as A, {} from 'path';", "import * as A, {} from 'path';",
"import { * as A } from 'path';", "import { * as A } from 'path';",
"import { * as 'A' } from 'path';",
"import { * as A-B } from 'path';",
"function f() { import 'path'; }", "function f() { import 'path'; }",
"import { 42 as A } from 'path';", "import { 42 as A } from 'path';",
"import { A-B as C } from 'path';", "import { A-B as C } from 'path';",
"import { 'A' as 'B' } from 'path';",
].forEach(function(code) { ].forEach(function(code) {
assert.throws(function() { assert.throws(function() {
UglifyJS.parse(code); UglifyJS.parse(code);
@@ -53,4 +61,49 @@ describe("import", function() {
}); });
}); });
}); });
it("Should interoperate with ESTree correctly", function() {
[
"import A from 'path';",
"import * as A from 'path';",
"import A, * as B from 'path';",
"import { '42' as A, B } from 'path';",
"import A, { '42' as B } from 'path';",
].forEach(function(code) {
var ast = UglifyJS.parse(code);
try {
var spidermonkey = ast.to_mozilla_ast();
} catch (ex) {
assert.fail("[to_mozilla_ast] " + ex.stack);
}
try {
var ast2 = UglifyJS.AST_Node.from_mozilla_ast(spidermonkey);
} catch (ex) {
assert.fail("[from_mozilla_ast] " + ex.stack);
}
assert.strictEqual(ast2.print_to_string(), ast.print_to_string(), [
"spidermonkey:",
ast.print_to_string(),
ast2.print_to_string(),
].join("\n"));
try {
var acorn_est = acorn.parse(code, {
ecmaVersion: "latest",
locations: true,
sourceType: "module",
});
} catch (ex) {
assert.fail("[acorn.parse] " + ex.stack);
}
try {
var ast3 = UglifyJS.AST_Node.from_mozilla_ast(acorn_est);
} catch (ex) {
assert.fail("[from_acorn] " + ex.stack);
}
assert.strictEqual(ast3.print_to_string(), ast.print_to_string(), [
"acorn:",
ast.print_to_string(),
ast3.print_to_string(),
].join("\n"));
});
});
}); });