From 99d626d23f0bac9b7318b08c2e92e11ed9ddaff2 Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Mon, 13 Oct 2014 03:26:49 +1100 Subject: [PATCH] add file class to simplify transforming --- lib/6to5/file.js | 102 ++++++++++++++++++ lib/6to5/transform.js | 91 +++------------- lib/6to5/transformers/array-comprehension.js | 10 +- lib/6to5/transformers/classes.js | 32 +++--- .../transformers/computed-property-names.js | 4 +- lib/6to5/transformers/destructuring.js | 22 ++-- lib/6to5/transformers/for-of.js | 6 +- .../property-method-assignment.js | 4 +- 8 files changed, 156 insertions(+), 115 deletions(-) create mode 100644 lib/6to5/file.js diff --git a/lib/6to5/file.js b/lib/6to5/file.js new file mode 100644 index 0000000000..253f5a6d6c --- /dev/null +++ b/lib/6to5/file.js @@ -0,0 +1,102 @@ +module.exports = File; + +var transform = require("./transform"); +var traverse = require("./traverse"); +var util = require("./util"); +var _ = require("lodash"); + +function File(opts) { + this.uids = {}; + this.opts = File.normaliseOptions(opts); + this.ast = {}; +} + +File.normaliseOptions = function (opts) { + opts = opts || {}; + + _.defaults(opts, { + blacklist: [], + whitelist: [], + sourceMap: false, + filename: "unknown", + format: {} + }); + + _.defaults(opts, { + sourceFileName: opts.filename, + sourceMapName: opts.filename + }); + + transform._ensureTransformerNames("blacklist", opts.blacklist); + transform._ensureTransformerNames("whitelist", opts.whitelist); + + return opts; +}; + +File.prototype.transform = function (ast) { + this.ast = ast; + + var self = this; + var opts = this.opts; + + _.each(transform.transformers, function (transformer, name) { + self.runTransformer(name, transformer); + }); + + var result = util.generate(ast, opts); + + if (opts.sourceMap === "inline") { + result.code += "\n" + util.sourceMapToComment(result.map); + } + + result.map = result.map || null; + result.ast = ast; + + return result; +}; + +File.prototype.generateUid = function (name) { + var uids = this.uids; + var i = uids[name] || 1; + + var id = name; + if (i > 1) id += i; + uids[name] = i + 1; + return "_" + id; +}; + +File.prototype.canRunTransformer = function (name) { + var opts = this.opts; + + var blacklist = opts.blacklist; + if (blacklist.length && _.contains(blacklist, name)) return false; + + var whitelist = opts.whitelist; + if (whitelist.length && !_.contains(whitelist, name)) return false; + + return true; +}; + +File.prototype.runTransformer = function (name, transformer) { + if (!this.canRunTransformer(name)) return; + + var self = this; + + var build = function (exit) { + return function (node, parent) { + var fns = transformer[node.type] || transformer.all; + if (!fns) return; + + var fn = fns.enter || fns; + if (exit) fn = fns.exit; + if (!fn || !_.isFunction(fn)) return; + + return fn(node, parent, self); + }; + }; + + traverse(this.ast, { + enter: build(), + exit: build(true) + }); +}; diff --git a/lib/6to5/transform.js b/lib/6to5/transform.js index 6bf572cc6d..1233403165 100644 --- a/lib/6to5/transform.js +++ b/lib/6to5/transform.js @@ -1,86 +1,21 @@ +module.exports = transform; + var sourceMap = require("source-map"); -var traverse = require("./traverse"); var recast = require("recast"); +var File = require("./file"); var util = require("./util"); var _ = require("lodash"); -var ensureTransformerNames = function (type, keys) { - _.each(keys, function (key) { - if (!transform.transformers[key]) { - throw new ReferenceError("unknown transformer " + key + " specified in " + type); - } - }); -}; - -var transform = module.exports = function (code, opts) { +function transform(code, opts) { opts = opts || {}; code = (code || "") + ""; - _.defaults(opts, { - blacklist: [], - whitelist: [], - sourceMap: false, - filename: "unknown", - format: {} - }); - - _.defaults(opts, { - sourceFileName: opts.filename, - sourceMapName: opts.filename - }); - - ensureTransformerNames("blacklist", opts.blacklist); - ensureTransformerNames("whitelist", opts.whitelist); + var file = new File(opts); return util.parse(opts, code, function (tree) { - return transform._run(code, tree, opts); + return file.transform(tree); }); -}; - -transform._run = function (code, tree, opts) { - var generateUid = util.buildUidGenerator(); - - _.each(transform.transformers, function (transformer, name) { - var blacklist = opts.blacklist; - if (blacklist.length && _.contains(blacklist, name)) return; - - var whitelist = opts.whitelist; - if (whitelist.length && !_.contains(whitelist, name)) return; - - transform._runTransformer(transformer, tree, opts, generateUid); - }); - - var result = util.generate(tree, opts); - - if (opts.sourceMap === "inline") { - result.code += "\n" + util.sourceMapToComment(result.map); - } - - result.map = result.map || null; - result.ast = tree; - - return result; -}; - -transform._runTransformer = function (transformer, tree, opts, generateUid) { - var build = function (exit) { - return function (node, parent) { - var fns = transformer[node.type] || transformer.all; - if (!fns) return; - - var fn = fns.enter || fns; - if (exit) fn = fns.exit; - if (!fn || !_.isFunction(fn)) return; - - return fn(node, parent, opts, generateUid); - }; - }; - - traverse(tree, { - enter: build(), - exit: build(true) - }); -}; +} transform.test = function (task, assert) { var actual = task.actual; @@ -111,12 +46,20 @@ transform.test = function (task, assert) { _.each(task.sourceMappings, function (mapping, i) { var pos = consumer.originalPositionFor(mapping.generated); - var msg = "source mapping " + ++i + " - generated: " + mapping.generated.line + ":" + mapping.generated.column; + var msg = "source mapping " + i + " - generated: " + mapping.generated.line + ":" + mapping.generated.column; assert.equal(pos.line + ":" + pos.column, mapping.original.line + ":" + mapping.original.column, msg); }); } }; +transform._ensureTransformerNames = function (type, keys) { + _.each(keys, function (key) { + if (!transform.transformers[key]) { + throw new ReferenceError("unknown transformer " + key + " specified in " + type); + } + }); +}; + transform.transformers = { modules: require("./transformers/modules"), computedPropertyNames: require("./transformers/computed-property-names"), @@ -130,7 +73,7 @@ transform.transformers = { propertyMethodAssignment: require("./transformers/property-method-assignment"), defaultParameters: require("./transformers/default-parameters"), generators: require("./transformers/generators"), - blockBinding: require("./transformers/block-binding"), + letScoping: require("./transformers/let-scoping"), restParameters: require("./transformers/rest-parameters"), destructuring: require("./transformers/destructuring"), forOf: require("./transformers/for-of"), diff --git a/lib/6to5/transformers/array-comprehension.js b/lib/6to5/transformers/array-comprehension.js index f7ba4ba315..e7eb3de107 100644 --- a/lib/6to5/transformers/array-comprehension.js +++ b/lib/6to5/transformers/array-comprehension.js @@ -1,6 +1,8 @@ var util = require("../util"); var _ = require("lodash"); +// TODO: support `arguments` and `this` inside + var single = function (node) { var block = node.blocks[0]; @@ -15,8 +17,8 @@ var single = function (node) { }); }; -var multiple = function (node, generateUid) { - var uid = generateUid("arr"); +var multiple = function (node, file) { + var uid = file.generateUid("arr"); var container = util.template("array-comprehension-container", { KEY: uid @@ -64,7 +66,7 @@ var multiple = function (node, generateUid) { return container; }; -exports.ComprehensionExpression = function (node, parent, opts, generateUid) { +exports.ComprehensionExpression = function (node, parent, file) { _.each(node.blocks, function (block) { if (!block.of) { throw util.errorWithNode(block, "for-in array comprehension is not supported"); @@ -74,6 +76,6 @@ exports.ComprehensionExpression = function (node, parent, opts, generateUid) { if (node.blocks.length === 1) { return single(node); } else { - return multiple(node, generateUid); + return multiple(node, file); } }; diff --git a/lib/6to5/transformers/classes.js b/lib/6to5/transformers/classes.js index d358409a29..6f11d8c1f0 100644 --- a/lib/6to5/transformers/classes.js +++ b/lib/6to5/transformers/classes.js @@ -3,14 +3,14 @@ var util = require("../util"); var b = require("ast-types").builders; var _ = require("lodash"); -exports.ClassDeclaration = function (node, parent, opts, generateUid) { +exports.ClassDeclaration = function (node, parent, file) { return b.variableDeclaration("var", [ - b.variableDeclarator(node.id, buildClass(node, generateUid)) + b.variableDeclarator(node.id, buildClass(node, file)) ]); }; -exports.ClassExpression = function (node, parent, opts, generateUid) { - return buildClass(node, generateUid); +exports.ClassExpression = function (node, parent, file) { + return buildClass(node, file); }; var getMemberExpressionObject = function (node) { @@ -20,15 +20,9 @@ var getMemberExpressionObject = function (node) { return node; }; -var buildClass = function (node, generateUid) { +var buildClass = function (node, file) { var superName = node.superClass; - var className = node.id; - - var noName = false; - if (!className) { - className = b.identifier(generateUid("class")); - noName = true; - } + var className = node.id || b.identifier(file.generateUid("class")); var superClassArgument = node.superClass; var superClassCallee = node.superClass; @@ -38,7 +32,7 @@ var buildClass = function (node, generateUid) { superClassArgument = superClassCallee = getMemberExpressionObject(superName); } else if (superName.type !== "Identifier") { superClassArgument = superName; - superClassCallee = superName = b.identifier(generateUid("ref")); + superClassCallee = superName = b.identifier(file.generateUid("ref")); } } @@ -49,8 +43,8 @@ var buildClass = function (node, generateUid) { var block = container.callee.body; var body = block.body; - if (noName) { - body[0].declarations[0].init.id = null; + if (node.id) { + body[0].declarations[0].init.id = className; } var returnStatement = body.pop(); @@ -135,10 +129,10 @@ var buildClassBody = function (body, className, superName, node) { }; var superIdentifier = function (superName, methodNode, methodName, node, parent) { - if (parent.property === node) return; - - // super(); -> ClassName.prototype.MethodName.call(this); - if (parent.type === "CallExpression" && parent.callee === node) { + if (parent.property === node) { + return; + } else if (parent.type === "CallExpression" && parent.callee === node) { + // super(); -> ClassName.prototype.MethodName.call(this); parent.arguments.unshift(b.thisExpression()); if (methodName === "constructor") { diff --git a/lib/6to5/transformers/computed-property-names.js b/lib/6to5/transformers/computed-property-names.js index 174c83f2c4..967bbbd5a5 100644 --- a/lib/6to5/transformers/computed-property-names.js +++ b/lib/6to5/transformers/computed-property-names.js @@ -3,7 +3,7 @@ var util = require("../util"); var b = require("ast-types").builders; var _ = require("lodash"); -exports.ObjectExpression = function (node, parent, opts, generateUid) { +exports.ObjectExpression = function (node, parent, file) { var hasComputed = false; var hasThis = false; @@ -25,7 +25,7 @@ exports.ObjectExpression = function (node, parent, opts, generateUid) { var templateName = "function-return-obj"; if (hasThis) templateName += "-this"; - var objId = b.identifier(generateUid("ref")); + var objId = b.identifier(file.generateUid("ref")); var container = util.template(templateName, { KEY: objId, diff --git a/lib/6to5/transformers/destructuring.js b/lib/6to5/transformers/destructuring.js index eb703d76ea..0dd0f2db4a 100644 --- a/lib/6to5/transformers/destructuring.js +++ b/lib/6to5/transformers/destructuring.js @@ -47,9 +47,9 @@ var pushArrayPattern = function (kind, nodes, pattern, parentId) { }); }; -var pushPattern = function (kind, nodes, pattern, parentId, generateUid) { +var pushPattern = function (kind, nodes, pattern, parentId, file) { if (parentId.type !== "MemberExpression" && parentId.type !== "Identifier") { - var key = generateUid("ref"); + var key = file.generateUid("ref"); nodes.push(util.template("variable-assign", { KEY: key, @@ -63,14 +63,14 @@ var pushPattern = function (kind, nodes, pattern, parentId, generateUid) { }; exports.ForInStatement = -exports.ForOfStatement = function (node, parent, opts, generateUid) { +exports.ForOfStatement = function (node, parent, file) { var declar = node.left; if (declar.type !== "VariableDeclaration") return; var pattern = declar.declarations[0].id; if (!util.isPattern(pattern)) return; - var key = b.identifier(generateUid("ref")); + var key = b.identifier(file.generateUid("ref")); node.left = b.variableDeclaration(declar.kind, [ b.variableDeclarator(key, null) ]); @@ -87,7 +87,7 @@ exports.ForOfStatement = function (node, parent, opts, generateUid) { exports.ArrowFunctionExpression = exports.FunctionDeclaration = -exports.FunctionExpression = function (node, parent, opts, generateUid) { +exports.FunctionExpression = function (node, parent, file) { var block = node.body; var nodes = []; @@ -97,8 +97,8 @@ exports.FunctionExpression = function (node, parent, opts, generateUid) { if (!util.isPattern(pattern)) return pattern; hasDestructuring = true; - var parentId = b.identifier(generateUid("ref")); - pushPattern("var", nodes, pattern, parentId, generateUid); + var parentId = b.identifier(file.generateUid("ref")); + pushPattern("var", nodes, pattern, parentId, file); return parentId; }); @@ -107,7 +107,7 @@ exports.FunctionExpression = function (node, parent, opts, generateUid) { block.body = nodes.concat(block.body || []); }; -exports.ExpressionStatement = function (node, parent, opts, generateUid) { +exports.ExpressionStatement = function (node, parent, file) { var expr = node.expression; if (expr.type !== "AssignmentExpression") return; @@ -115,7 +115,7 @@ exports.ExpressionStatement = function (node, parent, opts, generateUid) { var nodes = []; - var ref = b.identifier(generateUid("ref")); + var ref = b.identifier(file.generateUid("ref")); nodes.push(b.variableDeclaration("var", [ b.variableDeclarator(ref, expr.right) ])); @@ -125,7 +125,7 @@ exports.ExpressionStatement = function (node, parent, opts, generateUid) { return nodes; }; -exports.VariableDeclaration = function (node, parent, opts, generateUid) { +exports.VariableDeclaration = function (node, parent, file) { if (parent.type === "ForInStatement") return; var nodes = []; @@ -143,7 +143,7 @@ exports.VariableDeclaration = function (node, parent, opts, generateUid) { var patternId = declar.init; var pattern = declar.id; if (util.isPattern(pattern) && patternId) { - pushPattern(node.kind, nodes, pattern, patternId, generateUid); + pushPattern(node.kind, nodes, pattern, patternId, file); } else { nodes.push(buildVariableAssign(node.kind, declar.id, declar.init)); } diff --git a/lib/6to5/transformers/for-of.js b/lib/6to5/transformers/for-of.js index 0e24998be9..77912996a6 100644 --- a/lib/6to5/transformers/for-of.js +++ b/lib/6to5/transformers/for-of.js @@ -1,11 +1,11 @@ var util = require("../util"); var b = require("ast-types").builders; -exports.ForOfStatement = function (node, parent, opts, generateUid) { +exports.ForOfStatement = function (node, parent, file) { var left = node.left; var declar; - var stepKey = b.identifier(generateUid("step")); + var stepKey = b.identifier(file.generateUid("step")); var stepValueId = b.memberExpression(stepKey, b.identifier("value"), false); if (left.type === "Identifier") { @@ -19,7 +19,7 @@ exports.ForOfStatement = function (node, parent, opts, generateUid) { } var node2 = util.template("for-of", { - ITERATOR_KEY: generateUid("iterator"), + ITERATOR_KEY: file.generateUid("iterator"), STEP_KEY: stepKey, OBJECT: node.right }); diff --git a/lib/6to5/transformers/property-method-assignment.js b/lib/6to5/transformers/property-method-assignment.js index a37e2f9f54..ab8543d2b5 100644 --- a/lib/6to5/transformers/property-method-assignment.js +++ b/lib/6to5/transformers/property-method-assignment.js @@ -6,7 +6,7 @@ exports.Property = function (node) { if (node.method) node.method = false; }; -exports.ObjectExpression = function (node, parent, opts, generateUid) { +exports.ObjectExpression = function (node, parent, file) { var mutatorMap = {}; node.properties = node.properties.filter(function (prop) { @@ -20,7 +20,7 @@ exports.ObjectExpression = function (node, parent, opts, generateUid) { if (_.isEmpty(mutatorMap)) return; - var objId = b.identifier(generateUid("ref")) + var objId = b.identifier(file.generateUid("ref")); return util.template("object-define-properties-closure", { KEY: objId,