add file class to simplify transforming

This commit is contained in:
Sebastian McKenzie
2014-10-13 03:26:49 +11:00
parent 8f587fa833
commit 99d626d23f
8 changed files with 156 additions and 115 deletions

102
lib/6to5/file.js Normal file
View File

@@ -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)
});
};

View File

@@ -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"),

View File

@@ -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);
}
};

View File

@@ -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") {

View File

@@ -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,

View File

@@ -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));
}

View File

@@ -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
});

View File

@@ -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,