Attempt to close #968 by implementing the mozilla tree for ES6 code
This commit is contained in:
parent
569757d14d
commit
9f7246305c
|
|
@ -643,7 +643,7 @@ var AST_NameMapping = DEFNODE("NameMapping", "foreign_name name", {
|
|||
this.name._walk(visitor);
|
||||
});
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
var AST_Import = DEFNODE("Import", "imported_name imported_names module_name", {
|
||||
$documentation: "An `import` statement",
|
||||
|
|
|
|||
|
|
@ -71,12 +71,29 @@
|
|||
body: normalize_directives(M.body.map(from_moz))
|
||||
});
|
||||
},
|
||||
ArrayPattern: function(M) {
|
||||
return new AST_Destructuring({
|
||||
start: my_start_token(M),
|
||||
end: my_end_token(M),
|
||||
names: M.elements.map(from_moz),
|
||||
is_array: true
|
||||
});
|
||||
},
|
||||
ObjectPattern: function(M) {
|
||||
return new AST_Destructuring({
|
||||
start: my_start_token(M),
|
||||
end: my_end_token(M),
|
||||
names: M.properties.map(from_moz),
|
||||
});
|
||||
},
|
||||
FunctionDeclaration: function(M) {
|
||||
return new AST_Defun({
|
||||
start: my_start_token(M),
|
||||
end: my_end_token(M),
|
||||
name: from_moz(M.id),
|
||||
argnames: M.params.map(from_moz),
|
||||
is_generator: M.generator,
|
||||
async: M.async,
|
||||
body: normalize_directives(from_moz(M.body).body)
|
||||
});
|
||||
},
|
||||
|
|
@ -86,9 +103,19 @@
|
|||
end: my_end_token(M),
|
||||
name: from_moz(M.id),
|
||||
argnames: M.params.map(from_moz),
|
||||
is_generator: M.generator,
|
||||
async: M.async,
|
||||
body: normalize_directives(from_moz(M.body).body)
|
||||
});
|
||||
},
|
||||
ArrowFunctionExpression: function(M) {
|
||||
return new AST_Arrow({
|
||||
start: my_start_token(M),
|
||||
end: my_end_token(M),
|
||||
argnames: M.params.map(from_moz),
|
||||
body: from_moz(M.body)
|
||||
});
|
||||
},
|
||||
ExpressionStatement: function(M) {
|
||||
return new AST_SimpleStatement({
|
||||
start: my_start_token(M),
|
||||
|
|
@ -117,6 +144,16 @@
|
|||
key : key.type == "Identifier" ? key.name : key.value,
|
||||
value : from_moz(M.value)
|
||||
};
|
||||
if (M.method) {
|
||||
args.is_generator = M.value.generator;
|
||||
args.async = M.value.async;
|
||||
if (key.type == "Identifier") {
|
||||
args.key = new AST_SymbolMethod({ name: args.key });
|
||||
} else {
|
||||
args.key = from_moz(M.key);
|
||||
}
|
||||
return new AST_ConciseMethod(args);
|
||||
}
|
||||
if (M.kind == "init") return new AST_ObjectKeyVal(args);
|
||||
args.key = new AST_SymbolMethod({
|
||||
name: args.key
|
||||
|
|
@ -124,6 +161,30 @@
|
|||
args.value = new AST_Accessor(args.value);
|
||||
if (M.kind == "get") return new AST_ObjectGetter(args);
|
||||
if (M.kind == "set") return new AST_ObjectSetter(args);
|
||||
if (M.kind == "method") {
|
||||
args.async = M.value.async;
|
||||
args.is_generator = M.value.generator;
|
||||
args.quote = M.computed ? "\"" : null;
|
||||
return new AST_ConciseMethod(args);
|
||||
}
|
||||
},
|
||||
MethodDefinition: function(M) {
|
||||
var args = {
|
||||
start : my_start_token(M),
|
||||
end : my_end_token(M),
|
||||
key : from_moz(M.key),
|
||||
value : from_moz(M.value),
|
||||
static : M.static,
|
||||
};
|
||||
if (M.kind == "get") {
|
||||
return new AST_ObjectGetter(args);
|
||||
}
|
||||
if (M.kind == "set") {
|
||||
return new AST_ObjectSetter(args);
|
||||
}
|
||||
args.is_generator = M.value.generator;
|
||||
args.async = M.value.async;
|
||||
return new AST_ConciseMethod(args);
|
||||
},
|
||||
ArrayExpression: function(M) {
|
||||
return new AST_Array({
|
||||
|
|
@ -168,12 +229,81 @@
|
|||
});
|
||||
},
|
||||
VariableDeclaration: function(M) {
|
||||
return new (M.kind === "const" ? AST_Const : AST_Var)({
|
||||
return new (M.kind === "const" ? AST_Const :
|
||||
M.kind === "let" ? AST_Let : AST_Var)({
|
||||
start : my_start_token(M),
|
||||
end : my_end_token(M),
|
||||
definitions : M.declarations.map(from_moz)
|
||||
});
|
||||
},
|
||||
|
||||
ImportDeclaration: function(M) {
|
||||
var imported_name = null;
|
||||
var imported_names = null;
|
||||
M.specifiers.forEach(function (specifier) {
|
||||
if (specifier.type === "ImportSpecifier") {
|
||||
if (!imported_names) { imported_names = []; }
|
||||
imported_names.push(new AST_NameMapping({
|
||||
start: my_start_token(specifier),
|
||||
end: my_end_token(specifier),
|
||||
foreign_name: from_moz(specifier.imported),
|
||||
name: from_moz(specifier.local)
|
||||
}));
|
||||
} else if (specifier.type === "ImportDefaultSpecifier") {
|
||||
imported_name = from_moz(specifier.local);
|
||||
} else if (specifier.type === "ImportNamespaceSpecifier") {
|
||||
if (!imported_names) { imported_names = []; }
|
||||
imported_names.push(new AST_NameMapping({
|
||||
start: my_start_token(specifier),
|
||||
end: my_end_token(specifier),
|
||||
foreign_name: new AST_SymbolImportForeign({ name: "*" }),
|
||||
name: from_moz(specifier.local)
|
||||
}));
|
||||
}
|
||||
});
|
||||
return new AST_Import({
|
||||
start : my_start_token(M),
|
||||
end : my_end_token(M),
|
||||
imported_name: imported_name,
|
||||
imported_names : imported_names,
|
||||
module_name : from_moz(M.source)
|
||||
})
|
||||
},
|
||||
ExportAllDeclaration: function(M) {
|
||||
return new AST_Export({
|
||||
start: my_start_token(M),
|
||||
end: my_end_token(M),
|
||||
exported_names: [
|
||||
new AST_NameMapping({
|
||||
name: new AST_SymbolExportForeign({ name: "*" }),
|
||||
foreign_name: new AST_SymbolExportForeign({ name: "*" })
|
||||
})
|
||||
],
|
||||
module_name: from_moz(M.source)
|
||||
});
|
||||
},
|
||||
ExportNamedDeclaration: function(M) {
|
||||
return new AST_Export({
|
||||
start: my_start_token(M),
|
||||
end: my_end_token(M),
|
||||
exported_definition: from_moz(M.declaration),
|
||||
exported_names: M.specifiers && M.specifiers.map(function (specifier) {
|
||||
return new AST_NameMapping({
|
||||
foreign_name: from_moz(specifier.exported),
|
||||
name: from_moz(specifier.local)
|
||||
})
|
||||
}),
|
||||
module_name: from_moz(M.source)
|
||||
});
|
||||
},
|
||||
ExportDefaultDeclaration: function(M) {
|
||||
return new AST_Export({
|
||||
start: my_start_token(M),
|
||||
end: my_end_token(M),
|
||||
exported_value: from_moz(M.declaration),
|
||||
is_default: true
|
||||
});
|
||||
},
|
||||
Literal: function(M) {
|
||||
var val = M.value, args = {
|
||||
start : my_start_token(M),
|
||||
|
|
@ -201,12 +331,26 @@
|
|||
return new AST_RegExp(args);
|
||||
}
|
||||
},
|
||||
MetaProperty: function(M) {
|
||||
if (M.meta.name === "new" && M.property.name === "target") {
|
||||
return new AST_NewTarget({
|
||||
start: my_start_token(M),
|
||||
end: my_end_token(M)
|
||||
});
|
||||
}
|
||||
},
|
||||
Identifier: function(M) {
|
||||
var p = FROM_MOZ_STACK[FROM_MOZ_STACK.length - 2];
|
||||
return new ( p.type == "LabeledStatement" ? AST_Label
|
||||
: p.type == "VariableDeclarator" && p.id === M ? (p.kind == "const" ? AST_SymbolConst : AST_SymbolVar)
|
||||
: p.type == "VariableDeclarator" && p.id === M ? (p.kind == "const" ? AST_SymbolConst : p.kind == "let" ? AST_SymbolLet : AST_SymbolVar)
|
||||
: /Import.*Specifier/.test(p.type) ? (p.local === M ? AST_SymbolImport : AST_SymbolImportForeign)
|
||||
: p.type == "ExportSpecifier" ? (p.local === M ? AST_SymbolExport : AST_SymbolExportForeign)
|
||||
: p.type == "FunctionExpression" ? (p.id === M ? AST_SymbolLambda : AST_SymbolFunarg)
|
||||
: p.type == "FunctionDeclaration" ? (p.id === M ? AST_SymbolDefun : AST_SymbolFunarg)
|
||||
: p.type == "ArrowFunctionExpression" ? (p.params.indexOf(M) !== -1) ? AST_SymbolFunarg : AST_SymbolRef
|
||||
: p.type == "ClassExpression" ? (p.id === M ? AST_SymbolClass : AST_SymbolRef)
|
||||
: p.type == "ClassDeclaration" ? (p.id === M ? AST_SymbolDefClass : AST_SymbolRef)
|
||||
: p.type == "MethodDefinition" ? AST_SymbolMethod
|
||||
: p.type == "CatchClause" ? AST_SymbolCatch
|
||||
: p.type == "BreakStatement" || p.type == "ContinueStatement" ? AST_LabelRef
|
||||
: AST_SymbolRef)({
|
||||
|
|
@ -229,6 +373,17 @@
|
|||
});
|
||||
};
|
||||
|
||||
MOZ_TO_ME.ClassDeclaration =
|
||||
MOZ_TO_ME.ClassExpression = function From_Moz_Class(M) {
|
||||
return new AST_Class({
|
||||
start : my_start_token(M),
|
||||
end : my_end_token(M),
|
||||
name : from_moz(M.id),
|
||||
extends : from_moz(M.superClass),
|
||||
properties: M.body.body.map(from_moz)
|
||||
});
|
||||
};
|
||||
|
||||
map("EmptyStatement", AST_EmptyStatement);
|
||||
map("BlockStatement", AST_BlockStatement, "body@body");
|
||||
map("IfStatement", AST_If, "test>condition, consequent>body, alternate>alternative");
|
||||
|
|
@ -243,6 +398,9 @@
|
|||
map("DoWhileStatement", AST_Do, "test>condition, body>body");
|
||||
map("ForStatement", AST_For, "init>init, test>condition, update>step, body>body");
|
||||
map("ForInStatement", AST_ForIn, "left>init, right>object, body>body");
|
||||
map("ForOfStatement", AST_ForOf, "left>init, right>object, body>body");
|
||||
map("AwaitExpression", AST_Await, "argument>expression");
|
||||
map("RestElement", AST_Expansion, "argument>expression");
|
||||
map("DebuggerStatement", AST_Debugger);
|
||||
map("VariableDeclarator", AST_VarDef, "id>name, init>value");
|
||||
map("CatchClause", AST_Catch, "param>argname, body%body");
|
||||
|
|
@ -264,19 +422,50 @@
|
|||
type: "FunctionDeclaration",
|
||||
id: to_moz(M.name),
|
||||
params: M.argnames.map(to_moz),
|
||||
generator: M.is_generator,
|
||||
async: M.async,
|
||||
body: to_moz_scope("BlockStatement", M)
|
||||
}
|
||||
});
|
||||
|
||||
def_to_moz(AST_Function, function To_Moz_FunctionExpression(M) {
|
||||
def_to_moz(AST_Function, function To_Moz_FunctionExpression(M, parent) {
|
||||
var is_generator = parent.is_generator !== undefined ?
|
||||
parent.is_generator : M.is_generator
|
||||
return {
|
||||
type: "FunctionExpression",
|
||||
id: to_moz(M.name),
|
||||
params: M.argnames.map(to_moz),
|
||||
generator: is_generator,
|
||||
async: M.async,
|
||||
body: to_moz_scope("BlockStatement", M)
|
||||
}
|
||||
});
|
||||
|
||||
def_to_moz(AST_Arrow, function To_Moz_ArrowFunctionExpression(M) {
|
||||
var body = M.body instanceof Array ? {
|
||||
type: "BlockStatement",
|
||||
body: M.body.map(to_moz)
|
||||
} : to_moz(M.body);
|
||||
return {
|
||||
type: "ArrowFunctionExpression",
|
||||
params: M.argnames.map(to_moz),
|
||||
body: body
|
||||
}
|
||||
});
|
||||
|
||||
def_to_moz(AST_Destructuring, function To_Moz_ObjectPattern(M) {
|
||||
if (M.is_array) {
|
||||
return {
|
||||
type: "ArrayPattern",
|
||||
elements: M.names.map(to_moz)
|
||||
}
|
||||
}
|
||||
return {
|
||||
type: "ObjectPattern",
|
||||
properties: M.names.map(to_moz)
|
||||
};
|
||||
});
|
||||
|
||||
def_to_moz(AST_Directive, function To_Moz_Directive(M) {
|
||||
return {
|
||||
type: "ExpressionStatement",
|
||||
|
|
@ -324,11 +513,64 @@
|
|||
def_to_moz(AST_Definitions, function To_Moz_VariableDeclaration(M) {
|
||||
return {
|
||||
type: "VariableDeclaration",
|
||||
kind: M instanceof AST_Const ? "const" : "var",
|
||||
kind:
|
||||
M instanceof AST_Const ? "const" :
|
||||
M instanceof AST_Let ? "let" : "var",
|
||||
declarations: M.definitions.map(to_moz)
|
||||
};
|
||||
});
|
||||
|
||||
def_to_moz(AST_Export, function To_Moz_ExportDeclaration(M) {
|
||||
if (M.exported_names) {
|
||||
if (M.exported_names[0].name.name === "*") {
|
||||
return {
|
||||
type: "ExportAllDeclaration",
|
||||
source: to_moz(M.module_name)
|
||||
};
|
||||
}
|
||||
return {
|
||||
type: "ExportNamedDeclaration",
|
||||
specifiers: M.exported_names.map(function (name_mapping) {
|
||||
return {
|
||||
type: "ExportSpecifier",
|
||||
exported: to_moz(name_mapping.foreign_name),
|
||||
local: to_moz(name_mapping.name)
|
||||
};
|
||||
}),
|
||||
declaration: to_moz(M.exported_definition),
|
||||
source: to_moz(M.module_name)
|
||||
};
|
||||
}
|
||||
return {
|
||||
type: M.is_default ? "ExportDefaultDeclaration" : "ExportNamedDeclaration",
|
||||
declaration: to_moz(M.is_default ? M.exported_value : M.exported_definition)
|
||||
};
|
||||
});
|
||||
|
||||
def_to_moz(AST_Import, function To_Moz_ImportDeclaration(M) {
|
||||
var specifiers = [];
|
||||
if (M.imported_name) {
|
||||
specifiers.push({
|
||||
type: "ImportDefaultSpecifier",
|
||||
local: to_moz(M.imported_name)
|
||||
});
|
||||
}
|
||||
if (M.imported_names) {
|
||||
M.imported_names.forEach(function(name_mapping) {
|
||||
specifiers.push({
|
||||
type: "ImportSpecifier",
|
||||
local: to_moz(name_mapping.name),
|
||||
imported: to_moz(name_mapping.foreign_name)
|
||||
});
|
||||
});
|
||||
}
|
||||
return {
|
||||
type: "ImportDeclaration",
|
||||
specifiers: specifiers,
|
||||
source: to_moz(M.module_name)
|
||||
}
|
||||
});
|
||||
|
||||
def_to_moz(AST_Sequence, function To_Moz_SequenceExpression(M) {
|
||||
return {
|
||||
type: "SequenceExpression",
|
||||
|
|
@ -378,7 +620,7 @@
|
|||
};
|
||||
});
|
||||
|
||||
def_to_moz(AST_ObjectProperty, function To_Moz_Property(M) {
|
||||
def_to_moz(AST_ObjectProperty, function To_Moz_Property(M, parent) {
|
||||
var key = {
|
||||
type: "Literal",
|
||||
value: M.key instanceof AST_SymbolMethod ? M.key.name : M.key
|
||||
|
|
@ -393,6 +635,16 @@
|
|||
if (M instanceof AST_ObjectSetter) {
|
||||
kind = "set";
|
||||
}
|
||||
if (parent instanceof AST_Class) {
|
||||
return {
|
||||
type: "MethodDefinition",
|
||||
computed: !(M.key instanceof AST_Symbol),
|
||||
kind: kind,
|
||||
static: M.static,
|
||||
key: to_moz(M.key),
|
||||
value: to_moz(M.value)
|
||||
};
|
||||
}
|
||||
return {
|
||||
type: "Property",
|
||||
kind: kind,
|
||||
|
|
@ -401,6 +653,55 @@
|
|||
};
|
||||
});
|
||||
|
||||
def_to_moz(AST_ConciseMethod, function To_Moz_MethodDefinition(M, parent) {
|
||||
if (parent instanceof AST_Object) {
|
||||
return {
|
||||
type: "Property",
|
||||
computed: !(M.key instanceof AST_Symbol),
|
||||
kind: "init",
|
||||
method: true,
|
||||
shorthand: false,
|
||||
key: to_moz(M.key),
|
||||
value: to_moz(M.value)
|
||||
};
|
||||
}
|
||||
return {
|
||||
type: "MethodDefinition",
|
||||
computed: !(M.key instanceof AST_Symbol),
|
||||
kind: M.key === "constructor" ? "constructor" : "method",
|
||||
static: M.static,
|
||||
key: to_moz(M.key),
|
||||
value: to_moz(M.value)
|
||||
};
|
||||
});
|
||||
|
||||
def_to_moz(AST_Class, function To_Moz_Class(M) {
|
||||
var type = M instanceof AST_ClassExpression ? "ClassExpression" : "ClassDeclaration";
|
||||
return {
|
||||
type: type,
|
||||
superClass: to_moz(M.extends),
|
||||
id: M.name ? to_moz(M.name) : null,
|
||||
body: {
|
||||
type: "ClassBody",
|
||||
body: M.properties.map(to_moz)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
def_to_moz(AST_NewTarget, function To_Moz_MetaProperty(M) {
|
||||
return {
|
||||
type: "MetaProperty",
|
||||
meta: {
|
||||
type: "Identifier",
|
||||
name: "new"
|
||||
},
|
||||
property: {
|
||||
type: "Identifier",
|
||||
name: "target"
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
def_to_moz(AST_Symbol, function To_Moz_Identifier(M) {
|
||||
var def = M.definition();
|
||||
return {
|
||||
|
|
@ -586,13 +887,20 @@
|
|||
};
|
||||
|
||||
function def_to_moz(mytype, handler) {
|
||||
mytype.DEFMETHOD("to_mozilla_ast", function() {
|
||||
return set_moz_loc(this, handler(this));
|
||||
mytype.DEFMETHOD("to_mozilla_ast", function(parent) {
|
||||
return set_moz_loc(this, handler(this, parent));
|
||||
});
|
||||
};
|
||||
|
||||
var TO_MOZ_STACK = null;
|
||||
|
||||
function to_moz(node) {
|
||||
return node != null ? node.to_mozilla_ast() : null;
|
||||
if (TO_MOZ_STACK === null) { TO_MOZ_STACK = []; }
|
||||
TO_MOZ_STACK.push(node);
|
||||
var ast = node != null ? node.to_mozilla_ast(TO_MOZ_STACK[TO_MOZ_STACK.length - 2]) : null;
|
||||
TO_MOZ_STACK.pop();
|
||||
if (TO_MOZ_STACK.length === 0) { TO_MOZ_STACK = null; }
|
||||
return ast
|
||||
};
|
||||
|
||||
function to_moz_block(node) {
|
||||
|
|
|
|||
11
lib/parse.js
11
lib/parse.js
|
|
@ -1294,9 +1294,14 @@ function parse($TEXT, options) {
|
|||
|
||||
var body = _function_body(is("punc", "{"), false, is_async);
|
||||
|
||||
var end =
|
||||
body instanceof Array && body.length ? body[body.length - 1].end :
|
||||
body instanceof Array ? start :
|
||||
body.end;
|
||||
|
||||
return new AST_Arrow({
|
||||
start : start,
|
||||
end : body.end,
|
||||
end : end,
|
||||
async : is_async,
|
||||
argnames : argnames,
|
||||
body : body
|
||||
|
|
@ -1709,6 +1714,8 @@ function parse($TEXT, options) {
|
|||
}
|
||||
// the await expression is parsed as a unary expression in Babel
|
||||
return new AST_Await({
|
||||
start: prev(),
|
||||
end: S.token,
|
||||
expression : maybe_unary(true),
|
||||
});
|
||||
}
|
||||
|
|
@ -2478,7 +2485,7 @@ function parse($TEXT, options) {
|
|||
next();
|
||||
if (is_import && is("name", "as")) {
|
||||
next(); // The "as" word
|
||||
name = as_symbol(AST_SymbolImportForeign);
|
||||
name = as_symbol(is_import ? AST_SymbolImportForeign : AST_SymbolExportForeign);
|
||||
}
|
||||
names = [map_nameAsterisk(is_import, name)];
|
||||
}
|
||||
|
|
|
|||
57
test/input/spidermonkey/input.js
Normal file
57
test/input/spidermonkey/input.js
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import "mod-name";
|
||||
import Foo from "bar";
|
||||
import * as Food from "food"
|
||||
import { Bar, Baz } from "lel";
|
||||
import Bar, { Foo } from "lel";
|
||||
import { Bar as kex, Baz as food } from "lel";
|
||||
|
||||
const x = 0b01;
|
||||
let y = 6;
|
||||
|
||||
export default x;
|
||||
export const z = 4;
|
||||
export function fun() {}
|
||||
export * from "a.js";
|
||||
export {A} from "a.js";
|
||||
export {A, B} from "a.js";
|
||||
export {C};
|
||||
|
||||
(a, [b], {c:foo = 3}, ...d) => null;
|
||||
() => {}
|
||||
|
||||
async function f() { }
|
||||
function*gen() { }
|
||||
|
||||
class Class extends Object {
|
||||
constructor(...args) {
|
||||
}
|
||||
foo() {}
|
||||
}
|
||||
|
||||
x = class {
|
||||
static staticMethod() {}
|
||||
static get foo() {}
|
||||
static set bar() {}
|
||||
get x() {}
|
||||
set x(value) {}
|
||||
static() { /* "static" can be a method name! */ }
|
||||
get() { /* "get" can be a method name! */ }
|
||||
set() { /* "set" can be a method name! */ }
|
||||
*bar() {}
|
||||
static *baz() {}
|
||||
*['constructor']() {}
|
||||
static ['constructor']() {}
|
||||
}
|
||||
|
||||
y = {
|
||||
get x() {},
|
||||
set x(value) {},
|
||||
bar() {},
|
||||
*bar() {},
|
||||
*['constructor']() {}
|
||||
}
|
||||
console.log(new.target);
|
||||
console.log([10, ...[], 20, ...[30, 40], 50]["length"]);
|
||||
var { w: w1, ...V } = { w: 7, x: 1, y: 2 };
|
||||
for (const x of y) {}
|
||||
async function f1() { await x + y; }
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
var assert = require("assert");
|
||||
var fs = require("fs");
|
||||
var exec = require("child_process").exec;
|
||||
var uglify = require("../node");
|
||||
|
||||
|
|
@ -112,4 +113,15 @@ describe("spidermonkey export/import sanity test", function() {
|
|||
assert.strictEqual(counter_strings, tests[i].strings, "String count mismatch for test " + tests[i].input);
|
||||
}
|
||||
});
|
||||
|
||||
it("should output and parse ES6 code correctly", function() {
|
||||
var code = fs.readFileSync("test/input/spidermonkey/input.js", "utf-8");
|
||||
var uglify_ast = uglify.parse(code);
|
||||
var moz_ast = uglify_ast.to_mozilla_ast();
|
||||
var from_moz_ast = uglify.AST_Node.from_mozilla_ast(moz_ast);
|
||||
assert.strictEqual(
|
||||
from_moz_ast.print_to_string(),
|
||||
uglify_ast.print_to_string()
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user