From 6ae03a5dce5941e4adbcf4d489f55dbcccddc4aa Mon Sep 17 00:00:00 2001 From: Richard Eames Date: Tue, 18 Nov 2014 15:25:12 -0700 Subject: [PATCH 01/24] Added an interop commonjs loader. --- .../transformation/modules/common_interop.js | 157 ++++++++++++++++++ lib/6to5/transformation/transform.js | 9 +- 2 files changed, 162 insertions(+), 4 deletions(-) create mode 100644 lib/6to5/transformation/modules/common_interop.js diff --git a/lib/6to5/transformation/modules/common_interop.js b/lib/6to5/transformation/modules/common_interop.js new file mode 100644 index 0000000000..3984b90bf2 --- /dev/null +++ b/lib/6to5/transformation/modules/common_interop.js @@ -0,0 +1,157 @@ +module.exports = CommonJSInteropFormatter; + +var util = require("../../util"); +var t = require("../../types"); + +function CommonJSInteropFormatter(file) { + this.file = file; +} + +CommonJSInteropFormatter.prototype.import = function (node, nodes) { + // import "foo"; + nodes.push(util.template("require", { + //inherits: node, + + MODULE_NAME: node.source.raw + }, true)); +}; + +CommonJSInteropFormatter.prototype.importSpecifier = function (specifier, node, nodes) { + var variableName = t.getSpecifierName(specifier); +//console.log("HI") + // import foo from "foo"; + if (specifier.default) { + // var m_foo = require("foo"), foo = m_foo && (m_foo["default"] || m_foo); + var tmpId = util.getUid(t.identifier(variableName), this.file); + nodes.push( + t.variableDeclaration('var', [ + t.variableDeclarator(tmpId, + t.callExpression(t.identifier("require"), [node.source]) + ), + t.variableDeclarator(variableName, + t.binaryExpression( + "&&", + tmpId, + t.binaryExpression( + "||", + t.memberExpression( + tmpId, + t.identifier("default"), + true + ), + tmpId + ) + ) + ) + ]) + ); + return; + } + + var templateName = "require-assign"; + + // import * as bar from "foo"; + if (specifier.type !== "ImportBatchSpecifier") templateName += "-key"; + + nodes.push(util.template(templateName, { + //inherits: node.specifiers.length === 1 && node, + + VARIABLE_NAME: variableName, + MODULE_NAME: node.source.raw, + KEY: specifier.id + })); +}; + +CommonJSInteropFormatter.prototype.export = function (node, nodes) { + var declar = node.declaration; + + if (node.default) { + var ref = declar; + + if (t.isClass(ref) || t.isFunction(ref)) { + if (ref.id) { + nodes.push(t.toStatement(ref)); + ref = ref.id; + } + } + + nodes.push(util.template("exports-default", { + //inherits: node, + + VALUE: ref + }, true)); + } else { + var assign; + + if (t.isVariableDeclaration(declar)) { + var decl = declar.declarations[0]; + + if (decl.init) { + decl.init = util.template("exports-assign", { + //inherits: node, + + VALUE: decl.init, + KEY: decl.id + }); + } + + nodes.push(declar); + } else { + assign = util.template("exports-assign", { + //inherits: node, + + VALUE: declar.id, + KEY: declar.id + }, true); + + nodes.push(t.toStatement(declar)); + nodes.push(assign); + + if (t.isFunctionDeclaration(declar)) { + assign._blockHoist = true; + } + } + } +}; + +CommonJSInteropFormatter.prototype._exportSpecifier = function (getRef, specifier, node, nodes) { + var variableName = t.getSpecifierName(specifier); + + var inherits = false; + if (node.specifiers.length === 1) inherits = node; + + if (node.source) { + if (t.isExportBatchSpecifier(specifier)) { + // export * from "foo"; + nodes.push(util.template("exports-wildcard", { + //inherits: inherits, + + OBJECT: getRef() + }, true)); + } else { + // export { foo } from "test"; + nodes.push(util.template("exports-assign-key", { + //inherits: inherits, + + VARIABLE_NAME: variableName.name, + OBJECT: getRef(), + KEY: specifier.id + }, true)); + } + } else { + // export { foo }; + nodes.push(util.template("exports-assign", { + //inherits: inherits, + + VALUE: specifier.id, + KEY: variableName + }, true)); + } +}; + +CommonJSInteropFormatter.prototype.exportSpecifier = function (specifier, node, nodes) { + return this._exportSpecifier(function () { + return t.callExpression(t.identifier("require"), [node.source]); + }, specifier, node, nodes); +}; + diff --git a/lib/6to5/transformation/transform.js b/lib/6to5/transformation/transform.js index cc467086ac..a7646beea3 100644 --- a/lib/6to5/transformation/transform.js +++ b/lib/6to5/transformation/transform.js @@ -20,10 +20,11 @@ transform._ensureTransformerNames = function (type, keys) { transform.transformers = {}; transform.moduleFormatters = { - common: require("./modules/common"), - ignore: require("./modules/ignore"), - amd: require("./modules/amd"), - umd: require("./modules/umd") + common: require("./modules/common"), + commoninterop: require("./modules/common_interop"), + ignore: require("./modules/ignore"), + amd: require("./modules/amd"), + umd: require("./modules/umd") }; _.each({ From bc3502d6955772dd5d61032566b9ade1194bfe6c Mon Sep 17 00:00:00 2001 From: Richard Eames Date: Tue, 18 Nov 2014 15:29:59 -0700 Subject: [PATCH 02/24] Allow module transformers to be directly passed into opts. --- lib/6to5/file.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/6to5/file.js b/lib/6to5/file.js index d8ecb685bf..d26194a1e3 100644 --- a/lib/6to5/file.js +++ b/lib/6to5/file.js @@ -59,7 +59,7 @@ File.normaliseOptions = function (opts) { }; File.prototype.getModuleFormatter = function (type) { - var ModuleFormatter = transform.moduleFormatters[type]; + var ModuleFormatter = _.isFunction(type) ? type : transform.moduleFormatters[type]; if (!ModuleFormatter) { var loc = util.resolve(type); From f43a3dec4bee1af30f9d59e3ce74155c85cc7f3e Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Wed, 19 Nov 2014 12:09:41 +1100 Subject: [PATCH 03/24] more regenerator spring cleaning --- .../transformers/generators/emit.js | 43 +++++++++---------- .../transformers/generators/hoist.js | 6 +-- .../transformers/generators/leap.js | 21 +++++---- .../transformers/generators/meta.js | 4 +- .../transformers/generators/visit.js | 6 +-- 5 files changed, 37 insertions(+), 43 deletions(-) diff --git a/lib/6to5/transformation/transformers/generators/emit.js b/lib/6to5/transformation/transformers/generators/emit.js index a628d5a686..787e8b00a8 100644 --- a/lib/6to5/transformation/transformers/generators/emit.js +++ b/lib/6to5/transformation/transformers/generators/emit.js @@ -23,7 +23,7 @@ var n = types.namedTypes; function Emitter(contextId) { assert.ok(this instanceof Emitter); - n.Identifier.assert(contextId); + t.assertIdentifier(contextId); // In order to make sure the context object does not collide with // anything in the local scope, we might have to rename it, so we @@ -64,7 +64,7 @@ function loc() { // Sets the exact value of the given location to the offset of the next // Statement emitted. Emitter.prototype.mark = function(loc) { - n.Literal.assert(loc); + t.assertLiteral(loc); var index = this.listing.length; if (loc.value === -1) { loc.value = index; @@ -79,7 +79,7 @@ Emitter.prototype.mark = function(loc) { Emitter.prototype.emit = function(node) { if (t.isExpression(node)) node = t.expressionStatement(node); - n.Statement.assert(node); + t.assertStatement(node); this.listing.push(node); }; @@ -145,7 +145,7 @@ Emitter.prototype.stop = function(rval) { }; Emitter.prototype.setReturnValue = function(valuePath) { - n.Expression.assert(valuePath.value); + t.assertExpression(valuePath.value); this.emitAssign( this.contextProperty("rval"), @@ -154,7 +154,7 @@ Emitter.prototype.setReturnValue = function(valuePath) { }; Emitter.prototype.clearPendingException = function(tryLoc, assignee) { - n.Literal.assert(tryLoc); + t.assertLiteral(tryLoc); var catchCall = t.callExpression( this.contextProperty("catch", true), @@ -177,8 +177,8 @@ Emitter.prototype.jump = function(toLoc) { // Conditional jump. Emitter.prototype.jumpIf = function(test, toLoc) { - n.Expression.assert(test); - n.Literal.assert(toLoc); + t.assertExpression(test); + t.assertLiteral(toLoc); this.emit(t.ifStatement( test, @@ -191,8 +191,8 @@ Emitter.prototype.jumpIf = function(test, toLoc) { // Conditional jump, with the condition negated. Emitter.prototype.jumpIfNot = function(test, toLoc) { - n.Expression.assert(test); - n.Literal.assert(toLoc); + t.assertExpression(test); + t.assertLiteral(toLoc); var negatedTest; if (t.isUnaryExpression(test) && test.operator === "!") { @@ -352,7 +352,7 @@ Emitter.prototype.explode = function(path, ignoreResult) { var node = path.value; var self = this; - n.Node.assert(node); + n.Node.check(node); if (t.isStatement(node)) return self.explodeStatement(path); @@ -396,10 +396,10 @@ Emitter.prototype.explodeStatement = function(path, labelId) { var self = this; var after, head; - n.Statement.assert(stmt); + t.assertStatement(stmt); if (labelId) { - n.Identifier.assert(labelId); + t.assertIdentifier(labelId); } else { labelId = null; } @@ -502,7 +502,7 @@ Emitter.prototype.explodeStatement = function(path, labelId) { break; case "ForInStatement": - n.Identifier.assert(stmt.left); + t.assertIdentifier(stmt.left); head = loc(); after = loc(); @@ -586,7 +586,7 @@ Emitter.prototype.explodeStatement = function(path, labelId) { for (var i = cases.length - 1; i >= 0; --i) { var c = cases[i]; - n.SwitchCase.assert(c); + t.assertSwitchCase(c); if (c.test) { condition = t.conditionalExpression( @@ -706,7 +706,7 @@ Emitter.prototype.explodeStatement = function(path, labelId) { var catchScope = bodyPath.scope; var catchParamName = handler.param.name; - n.CatchClause.assert(catchScope.node); + t.assertCatchClause(catchScope.node); assert.strictEqual(catchScope.lookup(catchParamName), catchScope); types.visit(bodyPath, { @@ -770,11 +770,11 @@ Emitter.prototype.emitAbruptCompletion = function(record) { var abruptArgs = [t.literal(record.type)]; if (record.type === "break" || record.type === "continue") { - n.Literal.assert(record.target); + t.assertLiteral(record.target); abruptArgs[1] = record.target; } else if (record.type === "return" || record.type === "throw") { if (record.value) { - n.Expression.assert(record.value); + t.assertExpression(record.value); abruptArgs[1] = record.value; } } @@ -797,7 +797,7 @@ function isValidCompletion(record) { } if (type === "break" || type === "continue") { - return !_.has(record, "value") && t.isLiteral(record.target);; + return !_.has(record, "value") && t.isLiteral(record.target); } if (type === "return" || type === "throw") { @@ -807,7 +807,6 @@ function isValidCompletion(record) { return false; } - // Not all offsets into emitter.listing are potential jump targets. For // example, execution typically falls into the beginning of a try block // without jumping directly there. This method returns the current offset @@ -833,7 +832,7 @@ Emitter.prototype.getUnmarkedCurrentLoc = function() { // be costly and verbose to set context.prev before every statement. Emitter.prototype.updateContextPrevLoc = function(loc) { if (loc) { - n.Literal.assert(loc); + t.assertLiteral(loc); if (loc.value === -1) { // If an uninitialized location literal was passed in, set its value @@ -859,7 +858,7 @@ Emitter.prototype.explodeExpression = function(path, ignoreResult) { var expr = path.value; if (expr) { - n.Expression.assert(expr); + t.assertExpression(expr); } else { return expr; } @@ -868,7 +867,7 @@ Emitter.prototype.explodeExpression = function(path, ignoreResult) { var result, after; // Used optionally by several cases below. function finish(expr) { - n.Expression.assert(expr); + t.assertExpression(expr); if (ignoreResult) { self.emit(expr); } else { diff --git a/lib/6to5/transformation/transformers/generators/hoist.js b/lib/6to5/transformation/transformers/generators/hoist.js index 03b97c79db..6097c216d1 100644 --- a/lib/6to5/transformation/transformers/generators/hoist.js +++ b/lib/6to5/transformation/transformers/generators/hoist.js @@ -13,20 +13,18 @@ var types = require("ast-types"); var t = require("../../../types"); var _ = require("lodash"); -var n = types.namedTypes; - // The hoist function takes a FunctionExpression or FunctionDeclaration // and replaces any Declaration nodes in its body with assignments, then // returns a VariableDeclaration containing just the names of the removed // declarations. exports.hoist = function(funPath) { assert.ok(funPath instanceof types.NodePath); - n.Function.assert(funPath.value); + t.assertFunction(funPath.value); var vars = {}; function varDeclToExpr(vdec, includeIdentifiers) { - n.VariableDeclaration.assert(vdec); + t.assertVariableDeclaration(vdec); var exprs = []; vdec.declarations.forEach(function(dec) { diff --git a/lib/6to5/transformation/transformers/generators/leap.js b/lib/6to5/transformation/transformers/generators/leap.js index b6704d8ce2..6eb44d5f90 100644 --- a/lib/6to5/transformation/transformers/generators/leap.js +++ b/lib/6to5/transformation/transformers/generators/leap.js @@ -17,11 +17,10 @@ exports.LoopEntry = LoopEntry; exports.TryEntry = TryEntry; var assert = require("assert"); -var types = require("ast-types"); var util = require("util"); +var t = require("../../../types"); var inherits = util.inherits; -var n = types.namedTypes; function Entry() { assert.ok(this instanceof Entry); @@ -30,7 +29,7 @@ function Entry() { function FunctionEntry(returnLoc) { Entry.call(this); - n.Literal.assert(returnLoc); + t.assertLiteral(returnLoc); this.returnLoc = returnLoc; } @@ -40,11 +39,11 @@ inherits(FunctionEntry, Entry); function LoopEntry(breakLoc, continueLoc, label) { Entry.call(this); - n.Literal.assert(breakLoc); - n.Literal.assert(continueLoc); + t.assertLiteral(breakLoc); + t.assertLiteral(continueLoc); if (label) { - n.Identifier.assert(label); + t.assertIdentifier(label); } else { label = null; } @@ -59,7 +58,7 @@ inherits(LoopEntry, Entry); function SwitchEntry(breakLoc) { Entry.call(this); - n.Literal.assert(breakLoc); + t.assertLiteral(breakLoc); this.breakLoc = breakLoc; } @@ -69,7 +68,7 @@ inherits(SwitchEntry, Entry); function TryEntry(firstLoc, catchEntry, finallyEntry) { Entry.call(this); - n.Literal.assert(firstLoc); + t.assertLiteral(firstLoc); if (catchEntry) { assert.ok(catchEntry instanceof CatchEntry); @@ -96,8 +95,8 @@ inherits(TryEntry, Entry); function CatchEntry(firstLoc, paramId) { Entry.call(this); - n.Literal.assert(firstLoc); - n.Identifier.assert(paramId); + t.assertLiteral(firstLoc); + t.assertIdentifier(paramId); this.firstLoc = firstLoc; this.paramId = paramId; @@ -108,7 +107,7 @@ inherits(CatchEntry, Entry); function FinallyEntry(firstLoc) { Entry.call(this); - n.Literal.assert(firstLoc); + t.assertLiteral(firstLoc); this.firstLoc = firstLoc; } diff --git a/lib/6to5/transformation/transformers/generators/meta.js b/lib/6to5/transformation/transformers/generators/meta.js index a755da8019..72d297bf6a 100644 --- a/lib/6to5/transformation/transformers/generators/meta.js +++ b/lib/6to5/transformation/transformers/generators/meta.js @@ -19,7 +19,7 @@ var n = types.namedTypes; function makePredicate(propertyName, knownTypes) { function onlyChildren(node) { - n.Node.assert(node); + n.Node.check(node); // Assume no side effects until we find out otherwise. var result = false; @@ -44,7 +44,7 @@ function makePredicate(propertyName, knownTypes) { } function predicate(node) { - n.Node.assert(node); + n.Node.check(node); var meta = m(node); if (_.has(meta, propertyName)) return meta[propertyName]; diff --git a/lib/6to5/transformation/transformers/generators/visit.js b/lib/6to5/transformation/transformers/generators/visit.js index e9c0781291..a27672eca0 100644 --- a/lib/6to5/transformation/transformers/generators/visit.js +++ b/lib/6to5/transformation/transformers/generators/visit.js @@ -14,8 +14,6 @@ var hoist = require("./hoist").hoist; var types = require("ast-types"); var t = require("../../../types"); -var n = types.namedTypes; - var runtimeAsyncMethod = runtimeProperty("async"); var runtimeWrapMethod = runtimeProperty("wrap"); var runtimeMarkMethod = runtimeProperty("mark"); @@ -179,7 +177,7 @@ var visitor = types.PathVisitor.fromMethodsObject({ bodyPath.push(varDecl); } else { - n.FunctionExpression.assert(node); + t.assertFunctionExpression(node); return t.callExpression(runtimeMarkMethod, [node]); } } @@ -187,7 +185,7 @@ var visitor = types.PathVisitor.fromMethodsObject({ function shouldNotHoistAbove(stmtPath) { var value = stmtPath.value; - n.Statement.assert(value); + t.assertStatement(value); // If the first statement is a "use strict" declaration, make sure to // insert hoisted declarations afterwards. From 21b7f4120eabf1ae4887141bda35531b5889c26a Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Wed, 19 Nov 2014 12:09:54 +1100 Subject: [PATCH 04/24] add assertion checks into types --- lib/6to5/types/index.js | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/lib/6to5/types/index.js b/lib/6to5/types/index.js index fac701132a..3e13d640e0 100644 --- a/lib/6to5/types/index.js +++ b/lib/6to5/types/index.js @@ -2,14 +2,25 @@ var _ = require("lodash"); var t = exports; +var addAssert = function (type, is) { + t["assert" + type] = function (node, opts) { + opts = opts || {}; + if (!is(node, opts)) { + throw new Error("Expected type " + JSON.stringify(type) + " with option " + JSON.stringify(opts)); + } + }; +}; + // t.VISITOR_KEYS = require("./visitor-keys"); _.each(t.VISITOR_KEYS, function (keys, type) { - t["is" + type] = function (node, opts) { + var is = t["is" + type] = function (node, opts) { return node && node.type === type && t.shallowEqual(node, opts); }; + + addAssert(type, is); }); // @@ -43,17 +54,21 @@ _.each(t.ALIAS_KEYS, function (aliases, type) { _.each(_aliases, function (types, type) { t[type.toUpperCase() + "_TYPES"] = types; - t["is" + type] = function (node, opts) { + var is = t["is" + type] = function (node, opts) { return node && _.contains(types, node.type) && t.shallowEqual(node, opts); }; + + addAssert(type, is); }); // t.isExpression = function (node) { - return !t.isDeclaration(node); + return !t.isStatement(node); }; +addAssert("Expression", t.isExpression); + // t.shallowEqual = function (actual, expected) { From 0df0c696a93889f029982bf36d34346a039b1920 Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Wed, 19 Nov 2014 12:10:06 +1100 Subject: [PATCH 05/24] add util.arrayify and util.regexify --- lib/6to5/util.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/6to5/util.js b/lib/6to5/util.js index 4425c28036..99551e5174 100644 --- a/lib/6to5/util.js +++ b/lib/6to5/util.js @@ -37,6 +37,21 @@ exports.list = function (val) { return val ? val.split(",") : []; }; +exports.regexify = function (val) { + if (!val) return new RegExp; + if (_.isArray(val)) val = val.join("|"); + if (_.isString(val)) return new RegExp(val || ""); + if (_.isRegExp(val)) return val; + throw new TypeError("illegal type for regexify"); +}; + +exports.arrayify = function (val) { + if (!val) return []; + if (_.isString(val)) return exports.list(val); + if (_.isArray(val)) return val; + throw new TypeError("illegal type for arrayify"); +}; + exports.getUid = function (parent, file) { var node; From 03ce52fb7c4d2bf67f6605517f737c9508d8c391 Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Wed, 19 Nov 2014 12:10:59 +1100 Subject: [PATCH 06/24] use regexify and arrayify in register options --- lib/6to5/register.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/6to5/register.js b/lib/6to5/register.js index d34f447533..9dbd1bf589 100644 --- a/lib/6to5/register.js +++ b/lib/6to5/register.js @@ -1,6 +1,7 @@ require("./polyfill"); var sourceMapSupport = require("source-map-support"); +var util = require("./util"); var to5 = require("./index"); var _ = require("lodash"); @@ -100,11 +101,11 @@ module.exports = function (opts) { if (_.isRegExp(opts)) opts = { ignore: opts }; if (opts.ignoreRegex != null) opts.ignore = opts.ignoreRegex; - if (opts.only != null) onlyRegex = opts.only; - if (opts.ignore != null) ignoreRegex = opts.ignore; + if (opts.only != null) onlyRegex = util.regexify(opts.only); + if (opts.ignore != null) ignoreRegex = util.regexify(opts.ignore); - if (opts.extensions) hookExtensions(opts.extensions); + if (opts.extensions) hookExtensions(util.arrayify(opts.extensions)); - if (opts.blacklist) blacklist = opts.blacklist; - if (opts.whitelist) whitelist = opts.whitelist; + if (opts.blacklist) blacklist = util.arrayify(opts.blacklist); + if (opts.whitelist) whitelist = util.arrayify(opts.whitelist); }; From fa46f606555c603c547433d9e43774c507ba235b Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Wed, 19 Nov 2014 12:11:08 +1100 Subject: [PATCH 07/24] expose util as _util --- lib/6to5/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/6to5/index.js b/lib/6to5/index.js index 2585aab36d..924e08acb3 100644 --- a/lib/6to5/index.js +++ b/lib/6to5/index.js @@ -17,6 +17,9 @@ exports.polyfill = function () { exports.canCompile = util.canCompile; +// do not use this - this is for use by official maintained 6to5 plugins +exports._util = util; + exports.transform = transform; exports.transformFile = function (filename, opts, callback) { From 221d78d2e2dbf333465c0bf61130d46c79598602 Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Wed, 19 Nov 2014 12:12:16 +1100 Subject: [PATCH 08/24] arrayify whitelist and blacklist, inherit moduleRoot from sourceRoot and vice versa --- lib/6to5/file.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/6to5/file.js b/lib/6to5/file.js index d26194a1e3..24b3c7350d 100644 --- a/lib/6to5/file.js +++ b/lib/6to5/file.js @@ -39,6 +39,17 @@ File.normaliseOptions = function (opts) { // normalise windows path separators to unix opts.filename = opts.filename.replace(/\\/g, "/"); + opts.blacklist = util.arrayify(opts.blacklist); + opts.whitelist = util.arrayify(opts.whitelist); + + _.defaults(opts, { + moduleRoot: opts.sourceRoot + }); + + _.defaults(opts, { + sourceRoot: opts.moduleRoot + }); + _.defaults(opts, { filenameRelative: opts.filename }); From d9d84c60b542459fbb0c629519528cd200dfaba1 Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Wed, 19 Nov 2014 12:12:49 +1100 Subject: [PATCH 09/24] check for existence of node before checking it in let scoping --- lib/6to5/transformation/transformers/let-scoping.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/6to5/transformation/transformers/let-scoping.js b/lib/6to5/transformation/transformers/let-scoping.js index 7998e9e362..6741207e7e 100644 --- a/lib/6to5/transformation/transformers/let-scoping.js +++ b/lib/6to5/transformation/transformers/let-scoping.js @@ -260,7 +260,7 @@ LetScoping.prototype.checkFor = function () { return false; } - if (forParent && !node.label) { + if (forParent && node && !node.label) { if (t.isBreakStatement(node)) { has.hasBreak = true; replace = t.returnStatement(t.literal("break")); From 34599a21cb6da315412ea252c7e5385ed838b318 Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Wed, 19 Nov 2014 12:40:10 +1100 Subject: [PATCH 10/24] clean up common-interop module formatter --- lib/6to5/templates/interop-require.js | 3 + .../transformation/modules/common-interop.js | 29 ++++ .../transformation/modules/common_interop.js | 157 ------------------ lib/6to5/transformation/transform.js | 2 +- .../exports-default/actual.js | 8 + .../exports-default/expected.js | 13 ++ .../exports-from/actual.js | 6 + .../exports-from/expected.js | 15 ++ .../exports-named/actual.js | 5 + .../exports-named/expected.js | 9 + .../exports-variable/actual.js | 8 + .../exports-variable/expected.js | 13 ++ .../hoist-function-exports/actual.js | 11 ++ .../hoist-function-exports/expected.js | 13 ++ .../imports-default/actual.js | 2 + .../imports-default/expected.js | 9 + .../imports-glob/actual.js | 1 + .../imports-glob/expected.js | 3 + .../imports-mixing/actual.js | 1 + .../imports-mixing/expected.js | 9 + .../imports-named/actual.js | 4 + .../imports-named/expected.js | 8 + .../modules-common-interop/imports/actual.js | 3 + .../imports/expected.js | 7 + .../modules-common-interop/options.json | 3 + .../modules-common-interop/overview/actual.js | 12 ++ .../overview/expected.js | 22 +++ 27 files changed, 218 insertions(+), 158 deletions(-) create mode 100644 lib/6to5/templates/interop-require.js create mode 100644 lib/6to5/transformation/modules/common-interop.js delete mode 100644 lib/6to5/transformation/modules/common_interop.js create mode 100644 test/fixtures/transformation/modules-common-interop/exports-default/actual.js create mode 100644 test/fixtures/transformation/modules-common-interop/exports-default/expected.js create mode 100644 test/fixtures/transformation/modules-common-interop/exports-from/actual.js create mode 100644 test/fixtures/transformation/modules-common-interop/exports-from/expected.js create mode 100644 test/fixtures/transformation/modules-common-interop/exports-named/actual.js create mode 100644 test/fixtures/transformation/modules-common-interop/exports-named/expected.js create mode 100644 test/fixtures/transformation/modules-common-interop/exports-variable/actual.js create mode 100644 test/fixtures/transformation/modules-common-interop/exports-variable/expected.js create mode 100644 test/fixtures/transformation/modules-common-interop/hoist-function-exports/actual.js create mode 100644 test/fixtures/transformation/modules-common-interop/hoist-function-exports/expected.js create mode 100644 test/fixtures/transformation/modules-common-interop/imports-default/actual.js create mode 100644 test/fixtures/transformation/modules-common-interop/imports-default/expected.js create mode 100644 test/fixtures/transformation/modules-common-interop/imports-glob/actual.js create mode 100644 test/fixtures/transformation/modules-common-interop/imports-glob/expected.js create mode 100644 test/fixtures/transformation/modules-common-interop/imports-mixing/actual.js create mode 100644 test/fixtures/transformation/modules-common-interop/imports-mixing/expected.js create mode 100644 test/fixtures/transformation/modules-common-interop/imports-named/actual.js create mode 100644 test/fixtures/transformation/modules-common-interop/imports-named/expected.js create mode 100644 test/fixtures/transformation/modules-common-interop/imports/actual.js create mode 100644 test/fixtures/transformation/modules-common-interop/imports/expected.js create mode 100644 test/fixtures/transformation/modules-common-interop/options.json create mode 100644 test/fixtures/transformation/modules-common-interop/overview/actual.js create mode 100644 test/fixtures/transformation/modules-common-interop/overview/expected.js diff --git a/lib/6to5/templates/interop-require.js b/lib/6to5/templates/interop-require.js new file mode 100644 index 0000000000..b48ee8c30e --- /dev/null +++ b/lib/6to5/templates/interop-require.js @@ -0,0 +1,3 @@ +(function (obj) { + return obj && (obj["default"] || obj); +}) diff --git a/lib/6to5/transformation/modules/common-interop.js b/lib/6to5/transformation/modules/common-interop.js new file mode 100644 index 0000000000..97d64e828d --- /dev/null +++ b/lib/6to5/transformation/modules/common-interop.js @@ -0,0 +1,29 @@ +module.exports = CommonJSInteropFormatter; + +var CommonJSFormatter = require("./common"); +var util = require("../../util"); +var t = require("../../types"); + +function CommonJSInteropFormatter(file) { + this.file = file; +} + +util.inherits(CommonJSInteropFormatter, CommonJSFormatter); + +CommonJSInteropFormatter.prototype.importSpecifier = function (specifier, node, nodes) { + var variableName = t.getSpecifierName(specifier); + + // import foo from "foo"; + if (specifier.default) { + nodes.push(t.variableDeclaration("var", [ + t.variableDeclarator(variableName, + t.callExpression(this.file.addDeclaration("interop-require"), [util.template("require", { + MODULE_NAME: node.source.raw + })]) + ) + ])); + return; + } + + CommonJSFormatter.prototype.importSpecifier.apply(this, arguments); +}; diff --git a/lib/6to5/transformation/modules/common_interop.js b/lib/6to5/transformation/modules/common_interop.js deleted file mode 100644 index 3984b90bf2..0000000000 --- a/lib/6to5/transformation/modules/common_interop.js +++ /dev/null @@ -1,157 +0,0 @@ -module.exports = CommonJSInteropFormatter; - -var util = require("../../util"); -var t = require("../../types"); - -function CommonJSInteropFormatter(file) { - this.file = file; -} - -CommonJSInteropFormatter.prototype.import = function (node, nodes) { - // import "foo"; - nodes.push(util.template("require", { - //inherits: node, - - MODULE_NAME: node.source.raw - }, true)); -}; - -CommonJSInteropFormatter.prototype.importSpecifier = function (specifier, node, nodes) { - var variableName = t.getSpecifierName(specifier); -//console.log("HI") - // import foo from "foo"; - if (specifier.default) { - // var m_foo = require("foo"), foo = m_foo && (m_foo["default"] || m_foo); - var tmpId = util.getUid(t.identifier(variableName), this.file); - nodes.push( - t.variableDeclaration('var', [ - t.variableDeclarator(tmpId, - t.callExpression(t.identifier("require"), [node.source]) - ), - t.variableDeclarator(variableName, - t.binaryExpression( - "&&", - tmpId, - t.binaryExpression( - "||", - t.memberExpression( - tmpId, - t.identifier("default"), - true - ), - tmpId - ) - ) - ) - ]) - ); - return; - } - - var templateName = "require-assign"; - - // import * as bar from "foo"; - if (specifier.type !== "ImportBatchSpecifier") templateName += "-key"; - - nodes.push(util.template(templateName, { - //inherits: node.specifiers.length === 1 && node, - - VARIABLE_NAME: variableName, - MODULE_NAME: node.source.raw, - KEY: specifier.id - })); -}; - -CommonJSInteropFormatter.prototype.export = function (node, nodes) { - var declar = node.declaration; - - if (node.default) { - var ref = declar; - - if (t.isClass(ref) || t.isFunction(ref)) { - if (ref.id) { - nodes.push(t.toStatement(ref)); - ref = ref.id; - } - } - - nodes.push(util.template("exports-default", { - //inherits: node, - - VALUE: ref - }, true)); - } else { - var assign; - - if (t.isVariableDeclaration(declar)) { - var decl = declar.declarations[0]; - - if (decl.init) { - decl.init = util.template("exports-assign", { - //inherits: node, - - VALUE: decl.init, - KEY: decl.id - }); - } - - nodes.push(declar); - } else { - assign = util.template("exports-assign", { - //inherits: node, - - VALUE: declar.id, - KEY: declar.id - }, true); - - nodes.push(t.toStatement(declar)); - nodes.push(assign); - - if (t.isFunctionDeclaration(declar)) { - assign._blockHoist = true; - } - } - } -}; - -CommonJSInteropFormatter.prototype._exportSpecifier = function (getRef, specifier, node, nodes) { - var variableName = t.getSpecifierName(specifier); - - var inherits = false; - if (node.specifiers.length === 1) inherits = node; - - if (node.source) { - if (t.isExportBatchSpecifier(specifier)) { - // export * from "foo"; - nodes.push(util.template("exports-wildcard", { - //inherits: inherits, - - OBJECT: getRef() - }, true)); - } else { - // export { foo } from "test"; - nodes.push(util.template("exports-assign-key", { - //inherits: inherits, - - VARIABLE_NAME: variableName.name, - OBJECT: getRef(), - KEY: specifier.id - }, true)); - } - } else { - // export { foo }; - nodes.push(util.template("exports-assign", { - //inherits: inherits, - - VALUE: specifier.id, - KEY: variableName - }, true)); - } -}; - -CommonJSInteropFormatter.prototype.exportSpecifier = function (specifier, node, nodes) { - return this._exportSpecifier(function () { - return t.callExpression(t.identifier("require"), [node.source]); - }, specifier, node, nodes); -}; - diff --git a/lib/6to5/transformation/transform.js b/lib/6to5/transformation/transform.js index a7646beea3..a0ba465c72 100644 --- a/lib/6to5/transformation/transform.js +++ b/lib/6to5/transformation/transform.js @@ -21,7 +21,7 @@ transform.transformers = {}; transform.moduleFormatters = { common: require("./modules/common"), - commoninterop: require("./modules/common_interop"), + commonInterop: require("./modules/common-interop"), ignore: require("./modules/ignore"), amd: require("./modules/amd"), umd: require("./modules/umd") diff --git a/test/fixtures/transformation/modules-common-interop/exports-default/actual.js b/test/fixtures/transformation/modules-common-interop/exports-default/actual.js new file mode 100644 index 0000000000..62923e5c15 --- /dev/null +++ b/test/fixtures/transformation/modules-common-interop/exports-default/actual.js @@ -0,0 +1,8 @@ +export default 42; +export default {}; +export default []; +export default foo; +export default function () {} +export default class {} +export default function foo () {} +export default class Foo {} diff --git a/test/fixtures/transformation/modules-common-interop/exports-default/expected.js b/test/fixtures/transformation/modules-common-interop/exports-default/expected.js new file mode 100644 index 0000000000..9a3b8194a0 --- /dev/null +++ b/test/fixtures/transformation/modules-common-interop/exports-default/expected.js @@ -0,0 +1,13 @@ +"use strict"; + +exports["default"] = 42; +exports["default"] = {}; +exports["default"] = []; +exports["default"] = foo; +exports["default"] = function () {}; +exports["default"] = function () {}; +function foo() {} +exports["default"] = foo; +var Foo = function Foo() {}; + +exports["default"] = Foo; diff --git a/test/fixtures/transformation/modules-common-interop/exports-from/actual.js b/test/fixtures/transformation/modules-common-interop/exports-from/actual.js new file mode 100644 index 0000000000..60857f6542 --- /dev/null +++ b/test/fixtures/transformation/modules-common-interop/exports-from/actual.js @@ -0,0 +1,6 @@ +export * from "foo"; +export {foo} from "foo"; +export {foo, bar} from "foo"; +export {foo as bar} from "foo"; +export {foo as default} from "foo"; +export {foo as default, bar} from "foo"; diff --git a/test/fixtures/transformation/modules-common-interop/exports-from/expected.js b/test/fixtures/transformation/modules-common-interop/exports-from/expected.js new file mode 100644 index 0000000000..feaeac94ee --- /dev/null +++ b/test/fixtures/transformation/modules-common-interop/exports-from/expected.js @@ -0,0 +1,15 @@ +"use strict"; + +(function (obj) { + for (var i in obj) { + exports[i] = obj[i]; + } +})(require("foo")); + +exports.foo = require("foo").foo; +exports.foo = require("foo").foo; +exports.bar = require("foo").bar; +exports.bar = require("foo").foo; +exports["default"] = require("foo").foo; +exports["default"] = require("foo").foo; +exports.bar = require("foo").bar; diff --git a/test/fixtures/transformation/modules-common-interop/exports-named/actual.js b/test/fixtures/transformation/modules-common-interop/exports-named/actual.js new file mode 100644 index 0000000000..8515ace759 --- /dev/null +++ b/test/fixtures/transformation/modules-common-interop/exports-named/actual.js @@ -0,0 +1,5 @@ +export {foo}; +export {foo, bar}; +export {foo as bar}; +export {foo as default}; +export {foo as default, bar}; diff --git a/test/fixtures/transformation/modules-common-interop/exports-named/expected.js b/test/fixtures/transformation/modules-common-interop/exports-named/expected.js new file mode 100644 index 0000000000..ce378a6fb0 --- /dev/null +++ b/test/fixtures/transformation/modules-common-interop/exports-named/expected.js @@ -0,0 +1,9 @@ +"use strict"; + +exports.foo = foo; +exports.foo = foo; +exports.bar = bar; +exports.bar = foo; +exports["default"] = foo; +exports["default"] = foo; +exports.bar = bar; diff --git a/test/fixtures/transformation/modules-common-interop/exports-variable/actual.js b/test/fixtures/transformation/modules-common-interop/exports-variable/actual.js new file mode 100644 index 0000000000..b4629cc731 --- /dev/null +++ b/test/fixtures/transformation/modules-common-interop/exports-variable/actual.js @@ -0,0 +1,8 @@ +export var foo = 1; +export var foo2 = function () {}; +export var foo3; +export let foo4 = 2; +export let foo5; +export const foo6 = 3; +export function foo7 () {} +export class foo8 {} diff --git a/test/fixtures/transformation/modules-common-interop/exports-variable/expected.js b/test/fixtures/transformation/modules-common-interop/exports-variable/expected.js new file mode 100644 index 0000000000..886cf61824 --- /dev/null +++ b/test/fixtures/transformation/modules-common-interop/exports-variable/expected.js @@ -0,0 +1,13 @@ +"use strict"; + +exports.foo7 = foo7; +var foo = exports.foo = 1; +var foo2 = exports.foo2 = function () {}; +var foo3; +var foo4 = exports.foo4 = 2; +var foo5; +var foo6 = exports.foo6 = 3; +function foo7() {} +var foo8 = function foo8() {}; + +exports.foo8 = foo8; diff --git a/test/fixtures/transformation/modules-common-interop/hoist-function-exports/actual.js b/test/fixtures/transformation/modules-common-interop/hoist-function-exports/actual.js new file mode 100644 index 0000000000..3c40b7d1c1 --- /dev/null +++ b/test/fixtures/transformation/modules-common-interop/hoist-function-exports/actual.js @@ -0,0 +1,11 @@ +import { isEven } from "./evens"; + +export function nextOdd(n) { + return isEven(n) ? n + 1 : n + 2; +} + +export var isOdd = (function (isEven) { + return function (n) { + return !isEven(n); + }; +})(isEven); diff --git a/test/fixtures/transformation/modules-common-interop/hoist-function-exports/expected.js b/test/fixtures/transformation/modules-common-interop/hoist-function-exports/expected.js new file mode 100644 index 0000000000..5a074e1496 --- /dev/null +++ b/test/fixtures/transformation/modules-common-interop/hoist-function-exports/expected.js @@ -0,0 +1,13 @@ +"use strict"; + +exports.nextOdd = nextOdd; +var isEven = require("./evens").isEven; +function nextOdd(n) { + return isEven(n) ? n + 1 : n + 2; +} + +var isOdd = exports.isOdd = (function (isEven) { + return function (n) { + return !isEven(n); + }; +})(isEven); diff --git a/test/fixtures/transformation/modules-common-interop/imports-default/actual.js b/test/fixtures/transformation/modules-common-interop/imports-default/actual.js new file mode 100644 index 0000000000..e67418654c --- /dev/null +++ b/test/fixtures/transformation/modules-common-interop/imports-default/actual.js @@ -0,0 +1,2 @@ +import foo from "foo"; +import {default as foo} from "foo"; diff --git a/test/fixtures/transformation/modules-common-interop/imports-default/expected.js b/test/fixtures/transformation/modules-common-interop/imports-default/expected.js new file mode 100644 index 0000000000..a93b2668f9 --- /dev/null +++ b/test/fixtures/transformation/modules-common-interop/imports-default/expected.js @@ -0,0 +1,9 @@ +"use strict"; + +var _interopRequire = function (obj) { + return obj && (obj["default"] || obj); +}; + +var foo = _interopRequire(require("foo")); + +var foo = require("foo")["default"]; diff --git a/test/fixtures/transformation/modules-common-interop/imports-glob/actual.js b/test/fixtures/transformation/modules-common-interop/imports-glob/actual.js new file mode 100644 index 0000000000..e55c077500 --- /dev/null +++ b/test/fixtures/transformation/modules-common-interop/imports-glob/actual.js @@ -0,0 +1 @@ +import * as foo from "foo"; diff --git a/test/fixtures/transformation/modules-common-interop/imports-glob/expected.js b/test/fixtures/transformation/modules-common-interop/imports-glob/expected.js new file mode 100644 index 0000000000..e8c2d94a6a --- /dev/null +++ b/test/fixtures/transformation/modules-common-interop/imports-glob/expected.js @@ -0,0 +1,3 @@ +"use strict"; + +var foo = require("foo"); \ No newline at end of file diff --git a/test/fixtures/transformation/modules-common-interop/imports-mixing/actual.js b/test/fixtures/transformation/modules-common-interop/imports-mixing/actual.js new file mode 100644 index 0000000000..ef78c95b1c --- /dev/null +++ b/test/fixtures/transformation/modules-common-interop/imports-mixing/actual.js @@ -0,0 +1 @@ +import foo, {baz as xyz} from "foo"; diff --git a/test/fixtures/transformation/modules-common-interop/imports-mixing/expected.js b/test/fixtures/transformation/modules-common-interop/imports-mixing/expected.js new file mode 100644 index 0000000000..09ea4cec86 --- /dev/null +++ b/test/fixtures/transformation/modules-common-interop/imports-mixing/expected.js @@ -0,0 +1,9 @@ +"use strict"; + +var _interopRequire = function (obj) { + return obj && (obj["default"] || obj); +}; + +var foo = _interopRequire(require("foo")); + +var xyz = require("foo").baz; diff --git a/test/fixtures/transformation/modules-common-interop/imports-named/actual.js b/test/fixtures/transformation/modules-common-interop/imports-named/actual.js new file mode 100644 index 0000000000..83a766c62d --- /dev/null +++ b/test/fixtures/transformation/modules-common-interop/imports-named/actual.js @@ -0,0 +1,4 @@ +import {bar} from "foo"; +import {bar, baz} from "foo"; +import {bar as baz} from "foo"; +import {bar as baz, xyz} from "foo"; diff --git a/test/fixtures/transformation/modules-common-interop/imports-named/expected.js b/test/fixtures/transformation/modules-common-interop/imports-named/expected.js new file mode 100644 index 0000000000..ed81790165 --- /dev/null +++ b/test/fixtures/transformation/modules-common-interop/imports-named/expected.js @@ -0,0 +1,8 @@ +"use strict"; + +var bar = require("foo").bar; +var bar = require("foo").bar; +var baz = require("foo").baz; +var baz = require("foo").bar; +var baz = require("foo").bar; +var xyz = require("foo").xyz; \ No newline at end of file diff --git a/test/fixtures/transformation/modules-common-interop/imports/actual.js b/test/fixtures/transformation/modules-common-interop/imports/actual.js new file mode 100644 index 0000000000..222b6885ac --- /dev/null +++ b/test/fixtures/transformation/modules-common-interop/imports/actual.js @@ -0,0 +1,3 @@ +import "foo"; +import "foo-bar"; +import "./directory/foo-bar"; diff --git a/test/fixtures/transformation/modules-common-interop/imports/expected.js b/test/fixtures/transformation/modules-common-interop/imports/expected.js new file mode 100644 index 0000000000..f1a139f51a --- /dev/null +++ b/test/fixtures/transformation/modules-common-interop/imports/expected.js @@ -0,0 +1,7 @@ +"use strict"; + +require("foo"); + +require("foo-bar"); + +require("./directory/foo-bar"); diff --git a/test/fixtures/transformation/modules-common-interop/options.json b/test/fixtures/transformation/modules-common-interop/options.json new file mode 100644 index 0000000000..d5e2792eed --- /dev/null +++ b/test/fixtures/transformation/modules-common-interop/options.json @@ -0,0 +1,3 @@ +{ + "modules": "commonInterop" +} diff --git a/test/fixtures/transformation/modules-common-interop/overview/actual.js b/test/fixtures/transformation/modules-common-interop/overview/actual.js new file mode 100644 index 0000000000..a77d4d5dfa --- /dev/null +++ b/test/fixtures/transformation/modules-common-interop/overview/actual.js @@ -0,0 +1,12 @@ +import "foo"; +import "foo-bar"; +import "./directory/foo-bar"; +import foo from "foo"; +import * as foo from "foo"; +import {bar} from "foo"; +import {foo as bar} from "foo"; + +export {test}; +export var test = 5; + +export default test; diff --git a/test/fixtures/transformation/modules-common-interop/overview/expected.js b/test/fixtures/transformation/modules-common-interop/overview/expected.js new file mode 100644 index 0000000000..208d3a3d3b --- /dev/null +++ b/test/fixtures/transformation/modules-common-interop/overview/expected.js @@ -0,0 +1,22 @@ +"use strict"; + +var _interopRequire = function (obj) { + return obj && (obj["default"] || obj); +}; + +require("foo"); + +require("foo-bar"); + +require("./directory/foo-bar"); + +var foo = _interopRequire(require("foo")); + +var foo = require("foo"); + +var bar = require("foo").bar; +var bar = require("foo").foo; +exports.test = test; +var test = exports.test = 5; + +exports["default"] = test; From 5fca09514906e123a5891831b23dd9518d4f39e2 Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Wed, 19 Nov 2014 12:40:23 +1100 Subject: [PATCH 11/24] use commonInterop module formatter in 6to5/register --- lib/6to5/register.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/6to5/register.js b/lib/6to5/register.js index 9dbd1bf589..30fc5e5a82 100644 --- a/lib/6to5/register.js +++ b/lib/6to5/register.js @@ -72,7 +72,8 @@ var loader = function (m, filename) { var result = to5.transformFileSync(filename, { whitelist: whitelist, blacklist: blacklist, - sourceMap: true + sourceMap: true, + modules: "commonInterop" }); maps[filename] = result.map; From 8f4c4be8219932fdcbad4b23134b707de203846c Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Wed, 19 Nov 2014 12:40:35 +1100 Subject: [PATCH 12/24] generator: add existence check to printJoin --- lib/6to5/generation/generator.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/6to5/generation/generator.js b/lib/6to5/generation/generator.js index 82fce1f967..73511ec6a6 100644 --- a/lib/6to5/generation/generator.js +++ b/lib/6to5/generation/generator.js @@ -165,6 +165,8 @@ CodeGenerator.prototype.print = function (node, parent, opts) { }; CodeGenerator.prototype.printJoin = function (print, nodes, opts) { + if (!nodes || !nodes.length) return; + opts = opts || {}; var self = this; From 6822c854d46c42e0b1d23b6508fc885417e27eed Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Wed, 19 Nov 2014 12:40:44 +1100 Subject: [PATCH 13/24] add interop-require declaration --- lib/6to5/file.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/6to5/file.js b/lib/6to5/file.js index 24b3c7350d..c7222c989f 100644 --- a/lib/6to5/file.js +++ b/lib/6to5/file.js @@ -19,7 +19,7 @@ function File(opts) { } File.declarations = ["extends", "class-props", "slice", "apply-constructor", - "tagged-template-literal"]; + "tagged-template-literal", "interop-require"]; File.normaliseOptions = function (opts) { opts = _.cloneDeep(opts || {}); From 1a279703766cfe450a0cbdf99de58f69ff4afb03 Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Wed, 19 Nov 2014 12:51:14 +1100 Subject: [PATCH 14/24] publish acorn-6to5 as an npm package - fixes #187 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 58bbc14e7f..ddac2c3c8f 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "chokidar": "0.10.5", "source-map-support": "0.2.8", "esutils": "1.1.4", - "acorn-6to5": "https://github.com/6to5/acorn-6to5/archive/74d8e9bed20ba302d3504f53d0b1c649968959e1.tar.gz", + "acorn-6to5": "0.9.1-1", "estraverse": "^1.7.0", "private": "^0.1.6" }, From 81ec1e1f420e1f166d78cdc5fc99302e210fb0f2 Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Wed, 19 Nov 2014 12:54:54 +1100 Subject: [PATCH 15/24] remove unused variable in generators/meta --- lib/6to5/transformation/transformers/generators/meta.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/6to5/transformation/transformers/generators/meta.js b/lib/6to5/transformation/transformers/generators/meta.js index 72d297bf6a..3f00df264e 100644 --- a/lib/6to5/transformation/transformers/generators/meta.js +++ b/lib/6to5/transformation/transformers/generators/meta.js @@ -11,7 +11,6 @@ var assert = require("assert"); var types = require("ast-types"); var m = require("private").makeAccessor(); -var t = require("../../../types"); var _ = require("lodash"); var isArray = types.builtInTypes.array; From a884a26402489938636a0d26acd7e2db9acef884 Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Wed, 19 Nov 2014 13:28:01 +1100 Subject: [PATCH 16/24] revert acorn-6to5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ddac2c3c8f..1a5cd5f087 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "chokidar": "0.10.5", "source-map-support": "0.2.8", "esutils": "1.1.4", - "acorn-6to5": "0.9.1-1", + "acorn-6to5": "0.9.1-2", "estraverse": "^1.7.0", "private": "^0.1.6" }, From 7fc2fe41af2b25c1c04ab01f41cb7171534f624b Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Wed, 19 Nov 2014 13:46:00 +1100 Subject: [PATCH 17/24] fix bug in let scoping resulting in unneccesary replacement - closes #193, closes #185 --- .../transformers/let-scoping.js | 25 +++++++++++++------ .../let-scoping/exec-block-scoped/exec.js | 7 ++++++ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/lib/6to5/transformation/transformers/let-scoping.js b/lib/6to5/transformation/transformers/let-scoping.js index 6741207e7e..a56d6af6b7 100644 --- a/lib/6to5/transformation/transformers/let-scoping.js +++ b/lib/6to5/transformation/transformers/let-scoping.js @@ -88,6 +88,9 @@ LetScoping.prototype.run = function () { this.info = this.getInfo(); + // remap all let references that exist in upper scopes to their uid + this.remap(); + // this is a block within a `Function` so we can safely leave it be if (t.isFunction(this.parent)) return this.noClosure(); @@ -138,23 +141,29 @@ LetScoping.prototype.run = function () { }; /** - * There are no let references accessed within a closure so we can just traverse - * through this block and replace all references that exist in a higher scope to - * their uids. + * There are no let references accessed within a closure so we can just turn the + * lets into vars. */ LetScoping.prototype.noClosure = function () { - var replacements = this.info.duplicates; - var declarators = this.info.declarators; - var block = this.block; + standardiseLets(this.info.declarators); +}; - standardiseLets(declarators); +/** + * Traverse through block and replace all references that exist in a higher + * scope to their uids. + */ + +LetScoping.prototype.remap = function () { + var replacements = this.info.duplicates; + var block = this.block; if (_.isEmpty(replacements)) return; - var replace = function (node, parent) { + var replace = function (node, parent, scope) { if (!t.isIdentifier(node)) return; if (!t.isReferenced(node, parent)) return; + if (scope && scope.hasOwn(node.name)) return; node.name = replacements[node.name] || node.name; }; diff --git a/test/fixtures/transformation/let-scoping/exec-block-scoped/exec.js b/test/fixtures/transformation/let-scoping/exec-block-scoped/exec.js index 8b1fd6db2b..d90256cbb2 100644 --- a/test/fixtures/transformation/let-scoping/exec-block-scoped/exec.js +++ b/test/fixtures/transformation/let-scoping/exec-block-scoped/exec.js @@ -2,5 +2,12 @@ let x = 1; { let x = 2; assert.equal(x, 2); + { + let x = 3; + assert.equal(x, 3); + + x++; + assert.equal(x, 4); + } } assert.equal(x, 1); From f80f860bbcc8a439d4f27e22d7050077a23974d4 Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Wed, 19 Nov 2014 13:48:09 +1100 Subject: [PATCH 18/24] changelog for 1.12.21 --- CHANGELOG.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 010bca804f..179876d5b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,17 @@ +# 1.12.21 + + * Fix unneccesary let scoping replacement. + * Add `commonInterop` module formatter. Thanks [@Naddiseo](https://github.com/Naddiseo). + * Fix `return` outside of function body bug. Thanks [@brentburg](https://github.com/brentburg). + * Add more flexible option types. + # 1.12.20 * Append `sourceMappingURL` when using `bin/6to5` and output sourcemaps. # 1.12.19 - * Add `comments` option and `--remove-comments` flag. Thanks @[webpro](htps://github.com/webpro)! + * Add `comments` option and `--remove-comments` flag. Thanks [@webpro](htps://github.com/webpro). * Embed `regenerator`. # 1.12.18 @@ -13,7 +20,7 @@ # 1.12.17 - * Add `moduleName`, `sourceRoot` and `filenameRelative` options - thanks @[darvelo](https://github.com/darvelo)! + * Add `moduleName`, `sourceRoot` and `filenameRelative` options. Thanks [@darvelo](https://github.com/darvelo). * Traversal optimisations. # 1.12.16 From 50dee1a7547ffe716dc40f35d04782a089d17ea2 Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Wed, 19 Nov 2014 13:49:35 +1100 Subject: [PATCH 19/24] v1.12.21 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1a5cd5f087..4c29afa844 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "6to5", "description": "Turn ES6 code into readable vanilla ES5 with source maps", - "version": "1.12.20", + "version": "1.12.21", "author": "Sebastian McKenzie ", "homepage": "https://github.com/6to5/6to5", "repository": { From 55b3f84a2fdc00ba31603c63f99b61f7bef73f02 Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Wed, 19 Nov 2014 13:51:01 +1100 Subject: [PATCH 20/24] add sourceRoot and moduleRoot defaults to docs --- doc/usage.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/usage.md b/doc/usage.md index c27b25e5a2..02c845469b 100644 --- a/doc/usage.md +++ b/doc/usage.md @@ -115,10 +115,12 @@ to5.transformFile("filename.js", options, function (err, result) { sourceFileName: "filename", // The root from which all sources are relative + // Default: `moduleRoot` option. sourceRoot: "assets/scripts", // Optional prefix for the AMD module formatter that will be prepend to the // filename on module definitions + // Default: `sourceRoot` option. moduleRoot: "my-app", // Optionally replace all 6to5 helper declarations with a referenece to this From 8feb17dd23d41aa1af1e6bae916f4110eb82a7fa Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Wed, 19 Nov 2014 17:18:05 +1100 Subject: [PATCH 21/24] normalise whitespace after function keyword --- lib/6to5/generation/generators/types.js | 2 +- .../transformers/generators/emit.js | 78 +++++++++---------- .../transformers/generators/hoist.js | 18 ++--- .../transformers/generators/leap.js | 8 +- .../transformers/generators/meta.js | 2 +- .../transformers/generators/runtime.js | 32 ++++---- .../transformers/generators/visit.js | 6 +- 7 files changed, 73 insertions(+), 73 deletions(-) diff --git a/lib/6to5/generation/generators/types.js b/lib/6to5/generation/generators/types.js index 80c72b1a70..92b4b2509d 100644 --- a/lib/6to5/generation/generators/types.js +++ b/lib/6to5/generation/generators/types.js @@ -78,7 +78,7 @@ exports.Literal = function (node) { val = JSON.stringify(val); // escape unicode characters - val = val.replace(/[\u007f-\uffff]/g, function(c) { + val = val.replace(/[\u007f-\uffff]/g, function (c) { return "\\u" + ("0000" + c.charCodeAt(0).toString(16)).slice(-4); }); diff --git a/lib/6to5/transformation/transformers/generators/emit.js b/lib/6to5/transformation/transformers/generators/emit.js index 787e8b00a8..888065dee0 100644 --- a/lib/6to5/transformation/transformers/generators/emit.js +++ b/lib/6to5/transformation/transformers/generators/emit.js @@ -63,7 +63,7 @@ function loc() { // Sets the exact value of the given location to the offset of the next // Statement emitted. -Emitter.prototype.mark = function(loc) { +Emitter.prototype.mark = function (loc) { t.assertLiteral(loc); var index = this.listing.length; if (loc.value === -1) { @@ -77,7 +77,7 @@ Emitter.prototype.mark = function(loc) { return loc; }; -Emitter.prototype.emit = function(node) { +Emitter.prototype.emit = function (node) { if (t.isExpression(node)) node = t.expressionStatement(node); t.assertStatement(node); this.listing.push(node); @@ -85,20 +85,20 @@ Emitter.prototype.emit = function(node) { // Shorthand for emitting assignment statements. This will come in handy // for assignments to temporary variables. -Emitter.prototype.emitAssign = function(lhs, rhs) { +Emitter.prototype.emitAssign = function (lhs, rhs) { this.emit(this.assign(lhs, rhs)); return lhs; }; // Shorthand for an assignment statement. -Emitter.prototype.assign = function(lhs, rhs) { +Emitter.prototype.assign = function (lhs, rhs) { return t.expressionStatement( t.assignmentExpression("=", lhs, rhs)); }; // Convenience function for generating expressions like context.next, // context.sent, and context.rval. -Emitter.prototype.contextProperty = function(name, computed) { +Emitter.prototype.contextProperty = function (name, computed) { return t.memberExpression( this.contextId, computed ? t.literal(name) : t.identifier(name), @@ -116,7 +116,7 @@ var volatileContextPropertyNames = { // A "volatile" context property is a MemberExpression like context.sent // that should probably be stored in a temporary variable when there's a // possibility the property will get overwritten. -Emitter.prototype.isVolatileContextProperty = function(expr) { +Emitter.prototype.isVolatileContextProperty = function (expr) { if (t.isMemberExpression(expr)) { if (expr.computed) { // If it's a computed property such as context[couldBeAnything], @@ -136,7 +136,7 @@ Emitter.prototype.isVolatileContextProperty = function(expr) { }; // Shorthand for setting context.rval and jumping to `context.stop()`. -Emitter.prototype.stop = function(rval) { +Emitter.prototype.stop = function (rval) { if (rval) { this.setReturnValue(rval); } @@ -144,7 +144,7 @@ Emitter.prototype.stop = function(rval) { this.jump(this.finalLoc); }; -Emitter.prototype.setReturnValue = function(valuePath) { +Emitter.prototype.setReturnValue = function (valuePath) { t.assertExpression(valuePath.value); this.emitAssign( @@ -153,7 +153,7 @@ Emitter.prototype.setReturnValue = function(valuePath) { ); }; -Emitter.prototype.clearPendingException = function(tryLoc, assignee) { +Emitter.prototype.clearPendingException = function (tryLoc, assignee) { t.assertLiteral(tryLoc); var catchCall = t.callExpression( @@ -170,13 +170,13 @@ Emitter.prototype.clearPendingException = function(tryLoc, assignee) { // Emits code for an unconditional jump to the given location, even if the // exact value of the location is not yet known. -Emitter.prototype.jump = function(toLoc) { +Emitter.prototype.jump = function (toLoc) { this.emitAssign(this.contextProperty("next"), toLoc); this.emit(t.breakStatement()); }; // Conditional jump. -Emitter.prototype.jumpIf = function(test, toLoc) { +Emitter.prototype.jumpIf = function (test, toLoc) { t.assertExpression(test); t.assertLiteral(toLoc); @@ -190,7 +190,7 @@ Emitter.prototype.jumpIf = function(test, toLoc) { }; // Conditional jump, with the condition negated. -Emitter.prototype.jumpIfNot = function(test, toLoc) { +Emitter.prototype.jumpIfNot = function (test, toLoc) { t.assertExpression(test); t.assertLiteral(toLoc); @@ -217,11 +217,11 @@ Emitter.prototype.jumpIfNot = function(test, toLoc) { // other local variables, and since we just increment `nextTempId` // monotonically, uniqueness is assured. var nextTempId = 0; -Emitter.prototype.makeTempVar = function() { +Emitter.prototype.makeTempVar = function () { return this.contextProperty("t" + nextTempId++); }; -Emitter.prototype.getContextFunction = function(id) { +Emitter.prototype.getContextFunction = function (id) { var node = t.functionExpression( id || null, [this.contextId], @@ -244,7 +244,7 @@ Emitter.prototype.getContextFunction = function(id) { // // Each marked location in this.listing will correspond to one generated // case statement. -Emitter.prototype.getDispatchLoop = function() { +Emitter.prototype.getDispatchLoop = function () { var self = this; var cases = []; var current; @@ -253,7 +253,7 @@ Emitter.prototype.getDispatchLoop = function() { // case, we can skip the rest of the statements until the next case. var alreadyEnded = false; - self.listing.forEach(function(stmt, i) { + self.listing.forEach(function (stmt, i) { if (self.marked.hasOwnProperty(i)) { cases.push(t.switchCase(t.literal(i), current = [])); alreadyEnded = false; @@ -306,7 +306,7 @@ function isSwitchCaseEnder(stmt) { t.isThrowStatement(stmt); } -Emitter.prototype.getTryEntryList = function() { +Emitter.prototype.getTryEntryList = function () { if (this.tryEntries.length === 0) { // To avoid adding a needless [] to the majority of runtime.wrap // argument lists, force the caller to handle this case specially. @@ -316,7 +316,7 @@ Emitter.prototype.getTryEntryList = function() { var lastLocValue = 0; return t.arrayExpression( - this.tryEntries.map(function(tryEntry) { + this.tryEntries.map(function (tryEntry) { var thisLocValue = tryEntry.firstLoc.value; assert.ok(thisLocValue >= lastLocValue, "try entries out of order"); lastLocValue = thisLocValue; @@ -346,7 +346,7 @@ Emitter.prototype.getTryEntryList = function() { // No destructive modification of AST nodes. -Emitter.prototype.explode = function(path, ignoreResult) { +Emitter.prototype.explode = function (path, ignoreResult) { assert.ok(path instanceof types.NodePath); var node = path.value; @@ -389,7 +389,7 @@ function getDeclError(node) { JSON.stringify(node)); } -Emitter.prototype.explodeStatement = function(path, labelId) { +Emitter.prototype.explodeStatement = function (path, labelId) { assert.ok(path instanceof types.NodePath); var stmt = path.value; @@ -440,7 +440,7 @@ Emitter.prototype.explodeStatement = function(path, labelId) { self.jumpIfNot(self.explodeExpression(path.get("test")), after); self.leapManager.withEntry( new leap.LoopEntry(after, before, labelId), - function() { self.explodeStatement(path.get("body")); } + function () { self.explodeStatement(path.get("body")); } ); self.jump(before); self.mark(after); @@ -455,7 +455,7 @@ Emitter.prototype.explodeStatement = function(path, labelId) { self.mark(first); self.leapManager.withEntry( new leap.LoopEntry(after, test, labelId), - function() { self.explode(path.get("body")); } + function () { self.explode(path.get("body")); } ); self.mark(test); self.jumpIf(self.explodeExpression(path.get("test")), first); @@ -484,7 +484,7 @@ Emitter.prototype.explodeStatement = function(path, labelId) { self.leapManager.withEntry( new leap.LoopEntry(after, update, labelId), - function() { self.explodeStatement(path.get("body")); } + function () { self.explodeStatement(path.get("body")); } ); self.mark(update); @@ -543,7 +543,7 @@ Emitter.prototype.explodeStatement = function(path, labelId) { self.leapManager.withEntry( new leap.LoopEntry(after, head, labelId), - function() { self.explodeStatement(path.get("body")); } + function () { self.explodeStatement(path.get("body")); } ); self.jump(head); @@ -605,8 +605,8 @@ Emitter.prototype.explodeStatement = function(path, labelId) { self.leapManager.withEntry( new leap.SwitchEntry(after), - function() { - path.get("cases").each(function(casePath) { + function () { + path.get("cases").each(function (casePath) { var i = casePath.name; self.mark(caseLocs[i]); @@ -682,7 +682,7 @@ Emitter.prototype.explodeStatement = function(path, labelId) { self.tryEntries.push(tryEntry); self.updateContextPrevLoc(tryEntry.firstLoc); - self.leapManager.withEntry(tryEntry, function() { + self.leapManager.withEntry(tryEntry, function () { self.explodeStatement(path.get("block")); if (catchLoc) { @@ -710,7 +710,7 @@ Emitter.prototype.explodeStatement = function(path, labelId) { assert.strictEqual(catchScope.lookup(catchParamName), catchScope); types.visit(bodyPath, { - visitIdentifier: function(path) { + visitIdentifier: function (path) { if (path.value.name === catchParamName && path.scope.lookup(catchParamName) === catchScope) { return safeParam; @@ -719,7 +719,7 @@ Emitter.prototype.explodeStatement = function(path, labelId) { } }); - self.leapManager.withEntry(catchEntry, function() { + self.leapManager.withEntry(catchEntry, function () { self.explodeStatement(bodyPath); }); } @@ -727,7 +727,7 @@ Emitter.prototype.explodeStatement = function(path, labelId) { if (finallyLoc) { self.updateContextPrevLoc(self.mark(finallyLoc)); - self.leapManager.withEntry(finallyEntry, function() { + self.leapManager.withEntry(finallyEntry, function () { self.explodeStatement(path.get("finalizer")); }); @@ -754,7 +754,7 @@ Emitter.prototype.explodeStatement = function(path, labelId) { } }; -Emitter.prototype.emitAbruptCompletion = function(record) { +Emitter.prototype.emitAbruptCompletion = function (record) { if (!isValidCompletion(record)) { assert.ok( false, @@ -816,7 +816,7 @@ function isValidCompletion(record) { // statements). There's no logical harm in marking such locations as jump // targets, but minimizing the number of switch cases keeps the generated // code shorter. -Emitter.prototype.getUnmarkedCurrentLoc = function() { +Emitter.prototype.getUnmarkedCurrentLoc = function () { return t.literal(this.listing.length); }; @@ -830,7 +830,7 @@ Emitter.prototype.getUnmarkedCurrentLoc = function() { // would know the location of the current instruction with complete // precision at all times, but we don't have that luxury here, as it would // be costly and verbose to set context.prev before every statement. -Emitter.prototype.updateContextPrevLoc = function(loc) { +Emitter.prototype.updateContextPrevLoc = function (loc) { if (loc) { t.assertLiteral(loc); @@ -853,7 +853,7 @@ Emitter.prototype.updateContextPrevLoc = function(loc) { this.emitAssign(this.contextProperty("prev"), loc); }; -Emitter.prototype.explodeExpression = function(path, ignoreResult) { +Emitter.prototype.explodeExpression = function (path, ignoreResult) { assert.ok(path instanceof types.NodePath); var expr = path.value; @@ -964,7 +964,7 @@ Emitter.prototype.explodeExpression = function(path, ignoreResult) { return finish(t.callExpression( newCallee, - path.get("arguments").map(function(argPath) { + path.get("arguments").map(function (argPath) { return explodeViaTempVar(null, argPath); }) )); @@ -972,14 +972,14 @@ Emitter.prototype.explodeExpression = function(path, ignoreResult) { case "NewExpression": return finish(t.newExpression( explodeViaTempVar(null, path.get("callee")), - path.get("arguments").map(function(argPath) { + path.get("arguments").map(function (argPath) { return explodeViaTempVar(null, argPath); }) )); case "ObjectExpression": return finish(t.objectExpression( - path.get("properties").map(function(propPath) { + path.get("properties").map(function (propPath) { return t.property( propPath.value.kind, propPath.value.key, @@ -990,7 +990,7 @@ Emitter.prototype.explodeExpression = function(path, ignoreResult) { case "ArrayExpression": return finish(t.arrayExpression( - path.get("elements").map(function(elemPath) { + path.get("elements").map(function (elemPath) { return explodeViaTempVar(null, elemPath); }) )); @@ -998,7 +998,7 @@ Emitter.prototype.explodeExpression = function(path, ignoreResult) { case "SequenceExpression": var lastIndex = expr.expressions.length - 1; - path.get("expressions").each(function(exprPath) { + path.get("expressions").each(function (exprPath) { if (exprPath.name === lastIndex) { result = self.explodeExpression(exprPath, ignoreResult); } else { diff --git a/lib/6to5/transformation/transformers/generators/hoist.js b/lib/6to5/transformation/transformers/generators/hoist.js index 6097c216d1..b9772466ba 100644 --- a/lib/6to5/transformation/transformers/generators/hoist.js +++ b/lib/6to5/transformation/transformers/generators/hoist.js @@ -17,7 +17,7 @@ var _ = require("lodash"); // and replaces any Declaration nodes in its body with assignments, then // returns a VariableDeclaration containing just the names of the removed // declarations. -exports.hoist = function(funPath) { +exports.hoist = function (funPath) { assert.ok(funPath instanceof types.NodePath); t.assertFunction(funPath.value); @@ -27,7 +27,7 @@ exports.hoist = function(funPath) { t.assertVariableDeclaration(vdec); var exprs = []; - vdec.declarations.forEach(function(dec) { + vdec.declarations.forEach(function (dec) { vars[dec.id.name] = dec.id; if (dec.init) { @@ -49,7 +49,7 @@ exports.hoist = function(funPath) { } types.visit(funPath.get("body"), { - visitVariableDeclaration: function(path) { + visitVariableDeclaration: function (path) { var expr = varDeclToExpr(path.value, false); if (expr === null) { path.replace(); @@ -64,7 +64,7 @@ exports.hoist = function(funPath) { return false; }, - visitForStatement: function(path) { + visitForStatement: function (path) { var init = path.value.init; if (t.isVariableDeclaration(init)) { path.get("init").replace(varDeclToExpr(init, false)); @@ -72,7 +72,7 @@ exports.hoist = function(funPath) { this.traverse(path); }, - visitForInStatement: function(path) { + visitForInStatement: function (path) { var left = path.value.left; if (t.isVariableDeclaration(left)) { path.get("left").replace(varDeclToExpr(left, true)); @@ -80,7 +80,7 @@ exports.hoist = function(funPath) { this.traverse(path); }, - visitFunctionDeclaration: function(path) { + visitFunctionDeclaration: function (path) { var node = path.value; vars[node.id.name] = node.id; @@ -118,14 +118,14 @@ exports.hoist = function(funPath) { return false; }, - visitFunctionExpression: function() { + visitFunctionExpression: function () { // Don't descend into nested function expressions. return false; } }); var paramNames = {}; - funPath.get("params").each(function(paramPath) { + funPath.get("params").each(function (paramPath) { var param = paramPath.value; if (t.isIdentifier(param)) { paramNames[param.name] = param; @@ -137,7 +137,7 @@ exports.hoist = function(funPath) { var declarations = []; - Object.keys(vars).forEach(function(name) { + Object.keys(vars).forEach(function (name) { if (!_.has(paramNames, name)) { declarations.push(t.variableDeclarator(vars[name], null)); } diff --git a/lib/6to5/transformation/transformers/generators/leap.js b/lib/6to5/transformation/transformers/generators/leap.js index 6eb44d5f90..5cd289b501 100644 --- a/lib/6to5/transformation/transformers/generators/leap.js +++ b/lib/6to5/transformation/transformers/generators/leap.js @@ -124,7 +124,7 @@ function LeapManager(emitter) { this.entryStack = [new FunctionEntry(emitter.finalLoc)]; } -LeapManager.prototype.withEntry = function(entry, callback) { +LeapManager.prototype.withEntry = function (entry, callback) { assert.ok(entry instanceof Entry); this.entryStack.push(entry); try { @@ -135,7 +135,7 @@ LeapManager.prototype.withEntry = function(entry, callback) { } }; -LeapManager.prototype._findLeapLocation = function(property, label) { +LeapManager.prototype._findLeapLocation = function (property, label) { for (var i = this.entryStack.length - 1; i >= 0; --i) { var entry = this.entryStack[i]; var loc = entry[property]; @@ -154,10 +154,10 @@ LeapManager.prototype._findLeapLocation = function(property, label) { return null; }; -LeapManager.prototype.getBreakLoc = function(label) { +LeapManager.prototype.getBreakLoc = function (label) { return this._findLeapLocation("breakLoc", label); }; -LeapManager.prototype.getContinueLoc = function(label) { +LeapManager.prototype.getContinueLoc = function (label) { return this._findLeapLocation("continueLoc", label); }; diff --git a/lib/6to5/transformation/transformers/generators/meta.js b/lib/6to5/transformation/transformers/generators/meta.js index 3f00df264e..f7bb1248e6 100644 --- a/lib/6to5/transformation/transformers/generators/meta.js +++ b/lib/6to5/transformation/transformers/generators/meta.js @@ -35,7 +35,7 @@ function makePredicate(propertyName, knownTypes) { return result; } - types.eachField(node, function(name, child) { + types.eachField(node, function (name, child) { check(child); }); diff --git a/lib/6to5/transformation/transformers/generators/runtime.js b/lib/6to5/transformation/transformers/generators/runtime.js index 5257c4b937..2adc60afdd 100644 --- a/lib/6to5/transformation/transformers/generators/runtime.js +++ b/lib/6to5/transformation/transformers/generators/runtime.js @@ -38,19 +38,19 @@ var GFName = "GeneratorFunction"; if (GF.name !== GFName) GF.name = GFName; if (GF.name !== GFName) throw new Error(GFName + " renamed?"); -runtime.isGeneratorFunction = function(genFun) { +runtime.isGeneratorFunction = function (genFun) { var ctor = genFun && genFun.constructor; return ctor ? GF.name === ctor.name : false; }; -runtime.mark = function(genFun) { +runtime.mark = function (genFun) { genFun.__proto__ = GFp; genFun.prototype = Object.create(Gp); return genFun; }; -runtime.async = function(innerFn, outerFn, self, tryList) { - return new Promise(function(resolve, reject) { +runtime.async = function (innerFn, outerFn, self, tryList) { + return new Promise(function (resolve, reject) { var generator = wrap(innerFn, outerFn, self, tryList); var callNext = step.bind(generator.next); var callThrow = step.bind(generator["throw"]); @@ -202,11 +202,11 @@ function Generator(innerFn, outerFn, self, tryList) { return generator; } -Gp[iteratorSymbol] = function() { +Gp[iteratorSymbol] = function () { return this; }; -Gp.toString = function() { +Gp.toString = function () { return "[object Generator]"; }; @@ -240,7 +240,7 @@ function Context(tryList) { this.reset(); } -runtime.keys = function(object) { +runtime.keys = function (object) { var keys = []; for (var key in object) { keys.push(key); @@ -293,7 +293,7 @@ runtime.values = values; Context.prototype = { constructor: Context, - reset: function() { + reset: function () { this.prev = 0; this.next = 0; this.sent = undefined; @@ -311,7 +311,7 @@ Context.prototype = { } }, - stop: function() { + stop: function () { this.done = true; var rootEntry = this.tryEntries[0]; @@ -323,7 +323,7 @@ Context.prototype = { return this.rval; }, - dispatchException: function(exception) { + dispatchException: function (exception) { if (this.done) { throw exception; } @@ -375,7 +375,7 @@ Context.prototype = { } }, - _findFinallyEntry: function(finallyLoc) { + _findFinallyEntry: function (finallyLoc) { for (var i = this.tryEntries.length - 1; i >= 0; --i) { var entry = this.tryEntries[i]; if (entry.tryLoc <= this.prev && @@ -387,7 +387,7 @@ Context.prototype = { } }, - abrupt: function(type, arg) { + abrupt: function (type, arg) { var entry = this._findFinallyEntry(); var record = entry ? entry.completion : {}; @@ -403,7 +403,7 @@ Context.prototype = { return ContinueSentinel; }, - complete: function(record) { + complete: function (record) { if (record.type === "throw") { throw record.arg; } @@ -418,12 +418,12 @@ Context.prototype = { return ContinueSentinel; }, - finish: function(finallyLoc) { + finish: function (finallyLoc) { var entry = this._findFinallyEntry(finallyLoc); return this.complete(entry.completion); }, - "catch": function(tryLoc) { + "catch": function (tryLoc) { for (var i = this.tryEntries.length - 1; i >= 0; --i) { var entry = this.tryEntries[i]; if (entry.tryLoc === tryLoc) { @@ -442,7 +442,7 @@ Context.prototype = { throw new Error("illegal catch attempt"); }, - delegateYield: function(iterable, resultName, nextLoc) { + delegateYield: function (iterable, resultName, nextLoc) { this.delegate = { iterator: values(iterable), resultName: resultName, diff --git a/lib/6to5/transformation/transformers/generators/visit.js b/lib/6to5/transformation/transformers/generators/visit.js index a27672eca0..1c31a3e5a3 100644 --- a/lib/6to5/transformation/transformers/generators/visit.js +++ b/lib/6to5/transformation/transformers/generators/visit.js @@ -23,7 +23,7 @@ exports.transform = function transform(node) { }; var visitor = types.PathVisitor.fromMethodsObject({ - visitFunction: function(path) { + visitFunction: function (path) { // Calling this.traverse(path) first makes for a post-order traversal. this.traverse(path); @@ -208,11 +208,11 @@ function shouldNotHoistAbove(stmtPath) { } var awaitVisitor = types.PathVisitor.fromMethodsObject({ - visitFunction: function() { + visitFunction: function () { return false; // Don't descend into nested function scopes. }, - visitAwaitExpression: function(path) { + visitAwaitExpression: function (path) { // Convert await expressions to yield expressions. return t.yieldExpression(path.value.argument, false); } From 5c5d81164783718a399af606b1c91c70ffac2768 Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Wed, 19 Nov 2014 17:18:16 +1100 Subject: [PATCH 22/24] bump chokidar and fs-readdir-recursive versions --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 4c29afa844..7aeb3ca1ac 100644 --- a/package.json +++ b/package.json @@ -37,14 +37,14 @@ "dependencies": { "ast-types": "~0.6.0", "commander": "2.5.0", - "fs-readdir-recursive": "0.0.2", + "fs-readdir-recursive": "0.1.0", "lodash": "2.4.1", "mkdirp": "0.5.0", "es6-shim": "0.20.2", "es6-symbol": "0.1.1", "regexpu": "0.3.0", "source-map": "0.1.40", - "chokidar": "0.10.5", + "chokidar": "0.11.0", "source-map-support": "0.2.8", "esutils": "1.1.4", "acorn-6to5": "0.9.1-2", From d4379d52a7c8d6bd909232710a85fd825517ca34 Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Wed, 19 Nov 2014 17:48:59 +1100 Subject: [PATCH 23/24] split up generator transformer emit and explode --- .../generators/emit/explode-expressions.js | 204 +++++++ .../generators/emit/explode-statements.js | 334 +++++++++++ .../generators/{emit.js => emit/index.js} | 540 +----------------- .../transformers/generators/util.js | 10 + 4 files changed, 567 insertions(+), 521 deletions(-) create mode 100644 lib/6to5/transformation/transformers/generators/emit/explode-expressions.js create mode 100644 lib/6to5/transformation/transformers/generators/emit/explode-statements.js rename lib/6to5/transformation/transformers/generators/{emit.js => emit/index.js} (57%) diff --git a/lib/6to5/transformation/transformers/generators/emit/explode-expressions.js b/lib/6to5/transformation/transformers/generators/emit/explode-expressions.js new file mode 100644 index 0000000000..fe28897340 --- /dev/null +++ b/lib/6to5/transformation/transformers/generators/emit/explode-expressions.js @@ -0,0 +1,204 @@ +/** + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * https://raw.github.com/facebook/regenerator/master/LICENSE file. An + * additional grant of patent rights can be found in the PATENTS file in + * the same directory. + */ + +var assert = require("assert"); +var loc = require("../util").loc; +var t = require("../../../../types"); + +exports.ParenthesizedExpression = function (expr, path, explodeViaTempVar, finish) { + return finish(this.explodeExpression(path.get("expression"))); +}; + +exports.MemberExpression = function (expr, path, explodeViaTempVar, finish) { + return finish(t.memberExpression( + this.explodeExpression(path.get("object")), + expr.computed ? explodeViaTempVar(null, path.get("property")) : expr.property, + expr.computed + )); +}; + +exports.CallExpression = function (expr, path, explodeViaTempVar, finish) { + var oldCalleePath = path.get("callee"); + var newCallee = this.explodeExpression(oldCalleePath); + + // If the callee was not previously a MemberExpression, then the + // CallExpression was "unqualified," meaning its `this` object should + // be the global object. If the exploded expression has become a + // MemberExpression, then we need to force it to be unqualified by + // using the (0, object.property)(...) trick; otherwise, it will + // receive the object of the MemberExpression as its `this` object. + if (!t.isMemberExpression(oldCalleePath.node) && t.isMemberExpression(newCallee)) { + newCallee = t.sequenceExpression([ + t.literal(0), + newCallee + ]); + } + + return finish(t.callExpression( + newCallee, + path.get("arguments").map(function (argPath) { + return explodeViaTempVar(null, argPath); + }) + )); +}; + +exports.NewExpression = function (expr, path, explodeViaTempVar, finish) { + return finish(t.newExpression( + explodeViaTempVar(null, path.get("callee")), + path.get("arguments").map(function (argPath) { + return explodeViaTempVar(null, argPath); + }) + )); +}; + +exports.ObjectExpression = function (expr, path, explodeViaTempVar, finish) { + return finish(t.objectExpression( + path.get("properties").map(function (propPath) { + return t.property( + propPath.value.kind, + propPath.value.key, + explodeViaTempVar(null, propPath.get("value")) + ); + }) + )); +}; + +exports.ArrayExpression = function (expr, path, explodeViaTempVar, finish) { + return finish(t.arrayExpression( + path.get("elements").map(function (elemPath) { + return explodeViaTempVar(null, elemPath); + }) + )); +}; + +exports.SequenceExpression = function (expr, path, explodeViaTempVar, finish, ignoreResult) { + var lastIndex = expr.expressions.length - 1; + var self = this; + var result; + + path.get("expressions").each(function (exprPath) { + if (exprPath.name === lastIndex) { + result = self.explodeExpression(exprPath, ignoreResult); + } else { + self.explodeExpression(exprPath, true); + } + }); + + return result; +}; + +exports.LogicalExpression = function (expr, path, explodeViaTempVar, finish, ignoreResult) { + var after = loc(); + var result; + + if (!ignoreResult) { + result = this.makeTempVar(); + } + + var left = explodeViaTempVar(result, path.get("left")); + + if (expr.operator === "&&") { + this.jumpIfNot(left, after); + } else { + assert.strictEqual(expr.operator, "||"); + this.jumpIf(left, after); + } + + explodeViaTempVar(result, path.get("right"), ignoreResult); + + this.mark(after); + + return result; +}; + +exports.ConditionalExpression = function (expr, path, explodeViaTempVar, finish, ignoreResult) { + var elseLoc = loc(); + var after = loc(); + var test = this.explodeExpression(path.get("test")); + var result; + + this.jumpIfNot(test, elseLoc); + + if (!ignoreResult) { + result = this.makeTempVar(); + } + + explodeViaTempVar(result, path.get("consequent"), ignoreResult); + this.jump(after); + + this.mark(elseLoc); + explodeViaTempVar(result, path.get("alternate"), ignoreResult); + + this.mark(after); + + return result; +}; + +exports.UnaryExpression = function (expr, path, explodeViaTempVar, finish) { + return finish(t.unaryExpression( + expr.operator, + // Can't (and don't need to) break up the syntax of the argument. + // Think about delete a[b]. + this.explodeExpression(path.get("argument")), + !!expr.prefix + )); +}; + +exports.BinaryExpression = function (expr, path, explodeViaTempVar, finish) { + return finish(t.binaryExpression( + expr.operator, + explodeViaTempVar(null, path.get("left")), + explodeViaTempVar(null, path.get("right")) + )); +}; + +exports.AssignmentExpression = function (expr, path, explodeViaTempVar, finish) { + return finish(t.assignmentExpression( + expr.operator, + this.explodeExpression(path.get("left")), + this.explodeExpression(path.get("right")) + )); +}; + +exports.UpdateExpression = function (expr, path, explodeViaTempVar, finish) { + return finish(t.updateExpression( + expr.operator, + this.explodeExpression(path.get("argument")), + expr.prefix + )); +}; + +exports.YieldExpression = function (expr, path) { + var after = loc(); + var arg = expr.argument && this.explodeExpression(path.get("argument")); + var result; + + if (arg && expr.delegate) { + result = this.makeTempVar(); + + this.emit(t.returnStatement(t.callExpression( + this.contextProperty("delegateYield"), [ + arg, + t.literal(result.property.name), + after + ] + ))); + + this.mark(after); + + return result; + } + + this.emitAssign(this.contextProperty("next"), after); + this.emit(t.returnStatement(arg || null)); + this.mark(after); + + return this.contextProperty("sent"); +}; diff --git a/lib/6to5/transformation/transformers/generators/emit/explode-statements.js b/lib/6to5/transformation/transformers/generators/emit/explode-statements.js new file mode 100644 index 0000000000..9f73681883 --- /dev/null +++ b/lib/6to5/transformation/transformers/generators/emit/explode-statements.js @@ -0,0 +1,334 @@ +/** + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * https://raw.github.com/facebook/regenerator/master/LICENSE file. An + * additional grant of patent rights can be found in the PATENTS file in + * the same directory. + */ + +var assert = require("assert"); +var types = require("ast-types"); +var leap = require("../leap"); +var util = require("../util"); +var t = require("../../../../types"); + +var runtimeKeysMethod = util.runtimeProperty("keys"); +var loc = util.loc; + +exports.ExpressionStatement = function (path) { + this.explodeExpression(path.get("expression"), true); +}; + +exports.LabeledStatement = function (path, stmt) { + this.explodeStatement(path.get("body"), stmt.label); +}; + +exports.WhileStatement = function (path, stmt, labelId) { + var before = loc(); + var after = loc(); + + this.mark(before); + this.jumpIfNot(this.explodeExpression(path.get("test")), after); + this.leapManager.withEntry( + new leap.LoopEntry(after, before, labelId), + function () { this.explodeStatement(path.get("body")); } + ); + this.jump(before); + this.mark(after); +}; + +exports.DoWhileStatement = function (path, stmt, labelId) { + var first = loc(); + var test = loc(); + var after = loc(); + + this.mark(first); + this.leapManager.withEntry( + new leap.LoopEntry(after, test, labelId), + function () { this.explode(path.get("body")); } + ); + this.mark(test); + this.jumpIf(this.explodeExpression(path.get("test")), first); + this.mark(after); +}; + +exports.ForStatement = function (path, stmt, labelId) { + var head = loc(); + var update = loc(); + var after = loc(); + + if (stmt.init) { + // We pass true here to indicate that if stmt.init is an expression + // then we do not care about its result. + this.explode(path.get("init"), true); + } + + this.mark(head); + + if (stmt.test) { + this.jumpIfNot(this.explodeExpression(path.get("test")), after); + } else { + // No test means continue unconditionally. + } + + this.leapManager.withEntry( + new leap.LoopEntry(after, update, labelId), + function () { this.explodeStatement(path.get("body")); } + ); + + this.mark(update); + + if (stmt.update) { + // We pass true here to indicate that if stmt.update is an + // expression then we do not care about its result. + this.explode(path.get("update"), true); + } + + this.jump(head); + + this.mark(after); +}; + +exports.ForInStatement = function (path, stmt, labelId) { + t.assertIdentifier(stmt.left); + + var head = loc(); + var after = loc(); + + var keyIterNextFn = this.makeTempVar(); + this.emitAssign( + keyIterNextFn, + t.callExpression( + runtimeKeysMethod, + [this.explodeExpression(path.get("right"))] + ) + ); + + this.mark(head); + + var keyInfoTmpVar = this.makeTempVar(); + this.jumpIf( + t.memberExpression( + t.assignmentExpression( + "=", + keyInfoTmpVar, + t.callExpression(keyIterNextFn, []) + ), + t.identifier("done"), + false + ), + after + ); + + this.emitAssign( + stmt.left, + t.memberExpression( + keyInfoTmpVar, + t.identifier("value"), + false + ) + ); + + this.leapManager.withEntry( + new leap.LoopEntry(after, head, labelId), + function () { this.explodeStatement(path.get("body")); } + ); + + this.jump(head); + + this.mark(after); +}; + +exports.BreakStatement = function (path, stmt) { + this.emitAbruptCompletion({ + type: "break", + target: this.leapManager.getBreakLoc(stmt.label) + }); +}; + +exports.ContinueStatement = function (path, stmt) { + this.emitAbruptCompletion({ + type: "continue", + target: this.leapManager.getContinueLoc(stmt.label) + }); +}; + +exports.SwitchStatement = function (path, stmt) { + // Always save the discriminant into a temporary variable in case the + // test expressions overwrite values like context.sent. + var disc = this.emitAssign( + this.makeTempVar(), + this.explodeExpression(path.get("discriminant")) + ); + + var after = loc(); + var defaultLoc = loc(); + var condition = defaultLoc; + var caseLocs = []; + var self = this; + + // If there are no cases, .cases might be undefined. + var cases = stmt.cases || []; + + for (var i = cases.length - 1; i >= 0; --i) { + var c = cases[i]; + t.assertSwitchCase(c); + + if (c.test) { + condition = t.conditionalExpression( + t.binaryExpression("===", disc, c.test), + caseLocs[i] = loc(), + condition + ); + } else { + caseLocs[i] = defaultLoc; + } + } + + this.jump(this.explodeExpression( + new types.NodePath(condition, path, "discriminant") + )); + + this.leapManager.withEntry( + new leap.SwitchEntry(after), + function () { + path.get("cases").each(function (casePath) { + var i = casePath.name; + + self.mark(caseLocs[i]); + + casePath.get("consequent").each( + self.explodeStatement, + self + ); + }); + } + ); + + this.mark(after); + if (defaultLoc.value === -1) { + this.mark(defaultLoc); + assert.strictEqual(after.value, defaultLoc.value); + } +}; + +exports.IfStatement = function (path, stmt) { + var elseLoc = stmt.alternate && loc(); + var after = loc(); + + this.jumpIfNot( + this.explodeExpression(path.get("test")), + elseLoc || after + ); + + this.explodeStatement(path.get("consequent")); + + if (elseLoc) { + this.jump(after); + this.mark(elseLoc); + this.explodeStatement(path.get("alternate")); + } + + this.mark(after); +}; + +exports.ReturnStatement = function (path) { + this.emitAbruptCompletion({ + type: "return", + value: this.explodeExpression(path.get("argument")) + }); +}; + +exports.TryStatement = function (path, stmt) { + var after = loc(); + var self = this; + + var handler = stmt.handler; + if (!handler && stmt.handlers) { + handler = stmt.handlers[0] || null; + } + + var catchLoc = handler && loc(); + var catchEntry = catchLoc && new leap.CatchEntry( + catchLoc, + handler.param + ); + + var finallyLoc = stmt.finalizer && loc(); + var finallyEntry = finallyLoc && new leap.FinallyEntry(finallyLoc); + + var tryEntry = new leap.TryEntry( + this.getUnmarkedCurrentLoc(), + catchEntry, + finallyEntry + ); + + this.tryEntries.push(tryEntry); + this.updateContextPrevLoc(tryEntry.firstLoc); + + this.leapManager.withEntry(tryEntry, function () { + this.explodeStatement(path.get("block")); + + if (catchLoc) { + if (finallyLoc) { + // If we have both a catch block and a finally block, then + // because we emit the catch block first, we need to jump over + // it to the finally block. + this.jump(finallyLoc); + + } else { + // If there is no finally block, then we need to jump over the + // catch block to the fall-through location. + this.jump(after); + } + + this.updateContextPrevLoc(self.mark(catchLoc)); + + var bodyPath = path.get("handler", "body"); + var safeParam = this.makeTempVar(); + this.clearPendingException(tryEntry.firstLoc, safeParam); + + var catchScope = bodyPath.scope; + var catchParamName = handler.param.name; + t.assertCatchClause(catchScope.node); + assert.strictEqual(catchScope.lookup(catchParamName), catchScope); + + types.visit(bodyPath, { + visitIdentifier: function (path) { + if (path.value.name === catchParamName && + path.scope.lookup(catchParamName) === catchScope) { + return safeParam; + } + this.traverse(path); + } + }); + + this.leapManager.withEntry(catchEntry, function () { + this.explodeStatement(bodyPath); + }); + } + + if (finallyLoc) { + this.updateContextPrevLoc(this.mark(finallyLoc)); + + this.leapManager.withEntry(finallyEntry, function () { + this.explodeStatement(path.get("finalizer")); + }); + + this.emit(t.callExpression( + this.contextProperty("finish"), + [finallyEntry.firstLoc] + )); + } + }); + + this.mark(after); +}; + +exports.ThrowStatement = function (path) { + this.emit(t.throwStatement( + this.explodeExpression(path.get("argument")) + )); +}; diff --git a/lib/6to5/transformation/transformers/generators/emit.js b/lib/6to5/transformation/transformers/generators/emit/index.js similarity index 57% rename from lib/6to5/transformation/transformers/generators/emit.js rename to lib/6to5/transformation/transformers/generators/emit/index.js index 888065dee0..8df1576721 100644 --- a/lib/6to5/transformation/transformers/generators/emit.js +++ b/lib/6to5/transformation/transformers/generators/emit/index.js @@ -10,16 +10,18 @@ exports.Emitter = Emitter; -var runtimeProperty = require("./util").runtimeProperty; -var assert = require("assert"); -var types = require("ast-types"); -var leap = require("./leap"); -var meta = require("./meta"); -var t = require("../../../types"); -var _ = require("lodash"); +var explodeExpressions = require("./explode-expressions"); +var explodeStatements = require("./explode-statements"); +var assert = require("assert"); +var types = require("ast-types"); +var leap = require("../leap"); +var meta = require("../meta"); +var util = require("../util"); +var t = require("../../../../types"); +var _ = require("lodash"); -var runtimeKeysMethod = runtimeProperty("keys"); -var n = types.namedTypes; +var loc = util.loc; +var n = types.namedTypes; function Emitter(contextId) { assert.ok(this instanceof Emitter); @@ -52,15 +54,6 @@ function Emitter(contextId) { this.leapManager = new leap.LeapManager(this); } -// Offsets into this.listing that could be used as targets for branches or -// jumps are represented as numeric Literal nodes. This representation has -// the amazingly convenient benefit of allowing the exact value of the -// location to be determined at any time, even after generating code that -// refers to the location. -function loc() { - return t.literal(-1); -} - // Sets the exact value of the given location to the offset of the next // Statement emitted. Emitter.prototype.mark = function (loc) { @@ -394,7 +387,6 @@ Emitter.prototype.explodeStatement = function (path, labelId) { var stmt = path.value; var self = this; - var after, head; t.assertStatement(stmt); @@ -423,333 +415,10 @@ Emitter.prototype.explodeStatement = function (path, labelId) { return; } - switch (stmt.type) { - case "ExpressionStatement": - self.explodeExpression(path.get("expression"), true); - break; - - case "LabeledStatement": - self.explodeStatement(path.get("body"), stmt.label); - break; - - case "WhileStatement": - var before = loc(); - after = loc(); - - self.mark(before); - self.jumpIfNot(self.explodeExpression(path.get("test")), after); - self.leapManager.withEntry( - new leap.LoopEntry(after, before, labelId), - function () { self.explodeStatement(path.get("body")); } - ); - self.jump(before); - self.mark(after); - - break; - - case "DoWhileStatement": - var first = loc(); - var test = loc(); - after = loc(); - - self.mark(first); - self.leapManager.withEntry( - new leap.LoopEntry(after, test, labelId), - function () { self.explode(path.get("body")); } - ); - self.mark(test); - self.jumpIf(self.explodeExpression(path.get("test")), first); - self.mark(after); - - break; - - case "ForStatement": - head = loc(); - var update = loc(); - after = loc(); - - if (stmt.init) { - // We pass true here to indicate that if stmt.init is an expression - // then we do not care about its result. - self.explode(path.get("init"), true); - } - - self.mark(head); - - if (stmt.test) { - self.jumpIfNot(self.explodeExpression(path.get("test")), after); - } else { - // No test means continue unconditionally. - } - - self.leapManager.withEntry( - new leap.LoopEntry(after, update, labelId), - function () { self.explodeStatement(path.get("body")); } - ); - - self.mark(update); - - if (stmt.update) { - // We pass true here to indicate that if stmt.update is an - // expression then we do not care about its result. - self.explode(path.get("update"), true); - } - - self.jump(head); - - self.mark(after); - - break; - - case "ForInStatement": - t.assertIdentifier(stmt.left); - - head = loc(); - after = loc(); - - var keyIterNextFn = self.makeTempVar(); - self.emitAssign( - keyIterNextFn, - t.callExpression( - runtimeKeysMethod, - [self.explodeExpression(path.get("right"))] - ) - ); - - self.mark(head); - - var keyInfoTmpVar = self.makeTempVar(); - self.jumpIf( - t.memberExpression( - t.assignmentExpression( - "=", - keyInfoTmpVar, - t.callExpression(keyIterNextFn, []) - ), - t.identifier("done"), - false - ), - after - ); - - self.emitAssign( - stmt.left, - t.memberExpression( - keyInfoTmpVar, - t.identifier("value"), - false - ) - ); - - self.leapManager.withEntry( - new leap.LoopEntry(after, head, labelId), - function () { self.explodeStatement(path.get("body")); } - ); - - self.jump(head); - - self.mark(after); - - break; - - case "BreakStatement": - self.emitAbruptCompletion({ - type: "break", - target: self.leapManager.getBreakLoc(stmt.label) - }); - - break; - - case "ContinueStatement": - self.emitAbruptCompletion({ - type: "continue", - target: self.leapManager.getContinueLoc(stmt.label) - }); - - break; - - case "SwitchStatement": - // Always save the discriminant into a temporary variable in case the - // test expressions overwrite values like context.sent. - var disc = self.emitAssign( - self.makeTempVar(), - self.explodeExpression(path.get("discriminant")) - ); - - after = loc(); - var defaultLoc = loc(); - var condition = defaultLoc; - var caseLocs = []; - - // If there are no cases, .cases might be undefined. - var cases = stmt.cases || []; - - for (var i = cases.length - 1; i >= 0; --i) { - var c = cases[i]; - t.assertSwitchCase(c); - - if (c.test) { - condition = t.conditionalExpression( - t.binaryExpression("===", disc, c.test), - caseLocs[i] = loc(), - condition - ); - } else { - caseLocs[i] = defaultLoc; - } - } - - self.jump(self.explodeExpression( - new types.NodePath(condition, path, "discriminant") - )); - - self.leapManager.withEntry( - new leap.SwitchEntry(after), - function () { - path.get("cases").each(function (casePath) { - var i = casePath.name; - - self.mark(caseLocs[i]); - - casePath.get("consequent").each( - self.explodeStatement, - self - ); - }); - } - ); - - self.mark(after); - if (defaultLoc.value === -1) { - self.mark(defaultLoc); - assert.strictEqual(after.value, defaultLoc.value); - } - - break; - - case "IfStatement": - var elseLoc = stmt.alternate && loc(); - after = loc(); - - self.jumpIfNot( - self.explodeExpression(path.get("test")), - elseLoc || after - ); - - self.explodeStatement(path.get("consequent")); - - if (elseLoc) { - self.jump(after); - self.mark(elseLoc); - self.explodeStatement(path.get("alternate")); - } - - self.mark(after); - - break; - - case "ReturnStatement": - self.emitAbruptCompletion({ - type: "return", - value: self.explodeExpression(path.get("argument")) - }); - - break; - - case "TryStatement": - after = loc(); - - var handler = stmt.handler; - if (!handler && stmt.handlers) { - handler = stmt.handlers[0] || null; - } - - var catchLoc = handler && loc(); - var catchEntry = catchLoc && new leap.CatchEntry( - catchLoc, - handler.param - ); - - var finallyLoc = stmt.finalizer && loc(); - var finallyEntry = finallyLoc && new leap.FinallyEntry(finallyLoc); - - var tryEntry = new leap.TryEntry( - self.getUnmarkedCurrentLoc(), - catchEntry, - finallyEntry - ); - - self.tryEntries.push(tryEntry); - self.updateContextPrevLoc(tryEntry.firstLoc); - - self.leapManager.withEntry(tryEntry, function () { - self.explodeStatement(path.get("block")); - - if (catchLoc) { - if (finallyLoc) { - // If we have both a catch block and a finally block, then - // because we emit the catch block first, we need to jump over - // it to the finally block. - self.jump(finallyLoc); - - } else { - // If there is no finally block, then we need to jump over the - // catch block to the fall-through location. - self.jump(after); - } - - self.updateContextPrevLoc(self.mark(catchLoc)); - - var bodyPath = path.get("handler", "body"); - var safeParam = self.makeTempVar(); - self.clearPendingException(tryEntry.firstLoc, safeParam); - - var catchScope = bodyPath.scope; - var catchParamName = handler.param.name; - t.assertCatchClause(catchScope.node); - assert.strictEqual(catchScope.lookup(catchParamName), catchScope); - - types.visit(bodyPath, { - visitIdentifier: function (path) { - if (path.value.name === catchParamName && - path.scope.lookup(catchParamName) === catchScope) { - return safeParam; - } - this.traverse(path); - } - }); - - self.leapManager.withEntry(catchEntry, function () { - self.explodeStatement(bodyPath); - }); - } - - if (finallyLoc) { - self.updateContextPrevLoc(self.mark(finallyLoc)); - - self.leapManager.withEntry(finallyEntry, function () { - self.explodeStatement(path.get("finalizer")); - }); - - self.emit(t.callExpression( - self.contextProperty("finish"), - [finallyEntry.firstLoc] - )); - } - }); - - self.mark(after); - - break; - - case "ThrowStatement": - self.emit(t.throwStatement( - self.explodeExpression(path.get("argument")) - )); - - break; - - default: + var fn = explodeStatements[stmt.type]; + if (fn) { + fn.call(this, path, stmt, labelId); + } else { throw new Error("unknown Statement of type " + JSON.stringify(stmt.type)); } }; @@ -864,7 +533,6 @@ Emitter.prototype.explodeExpression = function (path, ignoreResult) { } var self = this; - var result, after; // Used optionally by several cases below. function finish(expr) { t.assertExpression(expr); @@ -934,180 +602,10 @@ Emitter.prototype.explodeExpression = function (path, ignoreResult) { // emitting the expression with all its side effects, and we should not // return a result. - switch (expr.type) { - case "ParenthesizedExpression": - return finish(self.explodeExpression(path.get("expression"))); - - case "MemberExpression": - return finish(t.memberExpression( - self.explodeExpression(path.get("object")), - expr.computed ? explodeViaTempVar(null, path.get("property")) : expr.property, - expr.computed - )); - - case "CallExpression": - var oldCalleePath = path.get("callee"); - var newCallee = self.explodeExpression(oldCalleePath); - - // If the callee was not previously a MemberExpression, then the - // CallExpression was "unqualified," meaning its `this` object should - // be the global object. If the exploded expression has become a - // MemberExpression, then we need to force it to be unqualified by - // using the (0, object.property)(...) trick; otherwise, it will - // receive the object of the MemberExpression as its `this` object. - if (!t.isMemberExpression(oldCalleePath.node) && t.isMemberExpression(newCallee)) { - newCallee = t.sequenceExpression([ - t.literal(0), - newCallee - ]); - } - - return finish(t.callExpression( - newCallee, - path.get("arguments").map(function (argPath) { - return explodeViaTempVar(null, argPath); - }) - )); - - case "NewExpression": - return finish(t.newExpression( - explodeViaTempVar(null, path.get("callee")), - path.get("arguments").map(function (argPath) { - return explodeViaTempVar(null, argPath); - }) - )); - - case "ObjectExpression": - return finish(t.objectExpression( - path.get("properties").map(function (propPath) { - return t.property( - propPath.value.kind, - propPath.value.key, - explodeViaTempVar(null, propPath.get("value")) - ); - }) - )); - - case "ArrayExpression": - return finish(t.arrayExpression( - path.get("elements").map(function (elemPath) { - return explodeViaTempVar(null, elemPath); - }) - )); - - case "SequenceExpression": - var lastIndex = expr.expressions.length - 1; - - path.get("expressions").each(function (exprPath) { - if (exprPath.name === lastIndex) { - result = self.explodeExpression(exprPath, ignoreResult); - } else { - self.explodeExpression(exprPath, true); - } - }); - - return result; - - case "LogicalExpression": - after = loc(); - - if (!ignoreResult) { - result = self.makeTempVar(); - } - - var left = explodeViaTempVar(result, path.get("left")); - - if (expr.operator === "&&") { - self.jumpIfNot(left, after); - } else { - assert.strictEqual(expr.operator, "||"); - self.jumpIf(left, after); - } - - explodeViaTempVar(result, path.get("right"), ignoreResult); - - self.mark(after); - - return result; - - case "ConditionalExpression": - var elseLoc = loc(); - after = loc(); - var test = self.explodeExpression(path.get("test")); - - self.jumpIfNot(test, elseLoc); - - if (!ignoreResult) { - result = self.makeTempVar(); - } - - explodeViaTempVar(result, path.get("consequent"), ignoreResult); - self.jump(after); - - self.mark(elseLoc); - explodeViaTempVar(result, path.get("alternate"), ignoreResult); - - self.mark(after); - - return result; - - case "UnaryExpression": - return finish(t.unaryExpression( - expr.operator, - // Can't (and don't need to) break up the syntax of the argument. - // Think about delete a[b]. - self.explodeExpression(path.get("argument")), - !!expr.prefix - )); - - case "BinaryExpression": - return finish(t.binaryExpression( - expr.operator, - explodeViaTempVar(null, path.get("left")), - explodeViaTempVar(null, path.get("right")) - )); - - case "AssignmentExpression": - return finish(t.assignmentExpression( - expr.operator, - self.explodeExpression(path.get("left")), - self.explodeExpression(path.get("right")) - )); - - case "UpdateExpression": - return finish(t.updateExpression( - expr.operator, - self.explodeExpression(path.get("argument")), - expr.prefix - )); - - case "YieldExpression": - after = loc(); - var arg = expr.argument && self.explodeExpression(path.get("argument")); - - if (arg && expr.delegate) { - result = self.makeTempVar(); - - self.emit(t.returnStatement(t.callExpression( - self.contextProperty("delegateYield"), [ - arg, - t.literal(result.property.name), - after - ] - ))); - - self.mark(after); - - return result; - } - - self.emitAssign(self.contextProperty("next"), after); - self.emit(t.returnStatement(arg || null)); - self.mark(after); - - return self.contextProperty("sent"); - - default: + var fn = explodeExpressions[expr.type]; + if (fn) { + return fn.call(this, expr, path, explodeViaTempVar, finish, ignoreResult); + } else { throw new Error("unknown Expression of type " + JSON.stringify(expr.type)); } }; diff --git a/lib/6to5/transformation/transformers/generators/util.js b/lib/6to5/transformation/transformers/generators/util.js index a6b5dc165f..99e7072a19 100644 --- a/lib/6to5/transformation/transformers/generators/util.js +++ b/lib/6to5/transformation/transformers/generators/util.js @@ -16,3 +16,13 @@ exports.runtimeProperty = function (name) { t.identifier(name) ); }; + +// Offsets into this.listing that could be used as targets for branches or +// jumps are represented as numeric Literal nodes. This representation has +// the amazingly convenient benefit of allowing the exact value of the +// location to be determined at any time, even after generating code that +// refers to the location. + +exports.loc = function () { + return t.literal(-1); +}; From 32b32329b29fa0fd1d6c30580bd5718b203a9e9a Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Wed, 19 Nov 2014 17:50:42 +1100 Subject: [PATCH 24/24] make umd module formatter inherit amd constructor --- lib/6to5/transformation/modules/umd.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/6to5/transformation/modules/umd.js b/lib/6to5/transformation/modules/umd.js index ea2f668a8e..c6777594e0 100644 --- a/lib/6to5/transformation/modules/umd.js +++ b/lib/6to5/transformation/modules/umd.js @@ -5,9 +5,8 @@ var util = require("../../util"); var t = require("../../types"); var _ = require("lodash"); -function UMDFormatter(file) { - this.file = file; - this.ids = {}; +function UMDFormatter() { + AMDFormatter.apply(this, arguments); } util.inherits(UMDFormatter, AMDFormatter);