add a transformer pass class

This commit is contained in:
Sebastian McKenzie
2015-01-26 22:10:19 +11:00
parent c49438da60
commit 971da50129
4 changed files with 102 additions and 65 deletions

View File

@@ -22,8 +22,9 @@ function File(opts) {
this.lastStatements = [];
this.opts = File.normaliseOptions(opts);
this.transformers = this.getTransformers();
this.ast = {};
this.buildTransformers();
}
File.helpers = [
@@ -145,17 +146,21 @@ File.prototype.isLoose = function (key) {
return _.contains(this.opts.loose, key);
};
File.prototype.getTransformers = function () {
File.prototype.buildTransformers = function () {
var file = this;
var transformers = [];
var secondPassTransformers = [];
_.each(transform.transformers, function (transformer) {
if (transformer.canRun(file)) {
transformers.push(transformer);
var transformers = {};
var secondaryStack = [];
var stack = [];
_.each(transform.transformers, function (transformer, key) {
var pass = transformers[key] = transformer.buildPass(file);
if (pass.canRun(file)) {
stack.push(pass);
if (transformer.secondPass) {
secondPassTransformers.push(transformer);
secondaryStack.push(pass);
}
if (transformer.manipulateOptions) {
@@ -164,7 +169,8 @@ File.prototype.getTransformers = function () {
}
});
return transformers.concat(secondPassTransformers);
this.transformerStack = stack.concat(secondaryStack);
this.transformers = transformers;
};
File.prototype.toArray = function (node, i) {
@@ -318,15 +324,15 @@ File.prototype.transform = function (ast) {
this.moduleFormatter = this.getModuleFormatter(this.opts.modules);
var astRun = function (key) {
_.each(self.transformers, function (transformer) {
transformer.astRun(self, key);
_.each(self.transformerStack, function (pass) {
pass.astRun(key);
});
};
astRun("enter");
_.each(this.transformers, function (transformer) {
transformer.transform(self);
_.each(this.transformerStack, function (pass) {
pass.transform();
});
astRun("exit");

View File

@@ -0,0 +1,69 @@
module.exports = TransformerPass;
var traverse = require("../traverse");
var _ = require("lodash");
/**
* This class is responsible for traversing over the provided `File`s
* AST and running it's parent transformers handlers over it.
*/
function TransformerPass(file, transformer) {
this.transformer = transformer;
this.handlers = transformer.handlers;
this.file = file;
}
TransformerPass.prototype.astRun = function (key) {
var handlers = this.handlers;
var file = this.file;
if (handlers.ast && handlers.ast[key]) {
handlers.ast[key](file.ast, file);
}
};
TransformerPass.prototype.canRun = function () {
var transformer = this.transformer;
var opts = this.file.opts;
var key = transformer.key;
if (key[0] === "_") return true;
var blacklist = opts.blacklist;
if (blacklist.length && _.contains(blacklist, key)) return false;
var whitelist = opts.whitelist;
if (whitelist.length && !_.contains(whitelist, key)) return false;
if (transformer.optional && !_.contains(opts.optional, key)) return false;
if (transformer.experimental && !opts.experimental) return false;
return true;
};
var transformVisitor = {
enter: function (node, parent, scope, context, state) {
var fns = state.handlers[node.type];
if (!fns) return;
return fns.enter(node, parent, scope, context, state.file, state.pass);
},
exit: function (node, parent, scope, context, state) {
var fns = state.handlers[node.type];
if (!fns) return;
return fns.exit(node, parent, scope, context, state.file, state.pass);
}
};
TransformerPass.prototype.transform = function () {
var file = this.file;
this.astRun("before");
var state = { file: file, handlers: this.handlers, pass: this };
traverse(file.ast, transformVisitor, file.scope, state);
this.astRun("after");
};

View File

@@ -2,16 +2,23 @@
module.exports = Transformer;
var traverse = require("../traverse");
var t = require("../types");
var _ = require("lodash");
var TransformerPass = require("./transformer-pass");
var traverse = require("../traverse");
var t = require("../types");
var _ = require("lodash");
/**
* This is the class responsible for normalising a transformers handlers
* as well as constructing a `TransformerPass` that is repsonsible for
* actually running the transformer over the provided `File`.
*/
function Transformer(key, transformer, opts) {
this.manipulateOptions = transformer.manipulateOptions;
this.experimental = !!transformer.experimental;
this.secondPass = !!transformer.secondPass;
this.transformer = this.normalise(transformer);
this.optional = !!transformer.optional;
this.handlers = this.normalise(transformer);
this.opts = opts || {};
this.key = key;
}
@@ -50,51 +57,6 @@ Transformer.prototype.normalise = function (transformer) {
return transformer;
};
Transformer.prototype.astRun = function (file, key) {
var transformer = this.transformer;
if (transformer.ast && transformer.ast[key]) {
transformer.ast[key](file.ast, file);
}
};
var transformVisitor = {
enter: function (node, parent, scope, context, state) {
var fns = state.transformer[node.type];
if (!fns) return;
return fns.enter(node, parent, scope, context, state.file);
},
exit: function (node, parent, scope, context, state) {
var fns = state.transformer[node.type];
if (!fns) return;
return fns.exit(node, parent, scope, context, state.file);
}
};
Transformer.prototype.transform = function (file) {
this.astRun(file, "before");
var state = { file: file, transformer: this.transformer };
traverse(file.ast, transformVisitor, file.scope, state);
this.astRun(file, "after");
};
Transformer.prototype.canRun = function (file) {
var opts = file.opts;
var key = this.key;
if (key[0] === "_") return true;
var blacklist = opts.blacklist;
if (blacklist.length && _.contains(blacklist, key)) return false;
var whitelist = opts.whitelist;
if (whitelist.length && !_.contains(whitelist, key)) return false;
if (this.optional && !_.contains(opts.optional, key)) return false;
if (this.experimental && !opts.experimental) return false;
return true;
Transformer.prototype.buildPass = function (file) {
return new TransformerPass(file, this);
};

View File

@@ -5,7 +5,7 @@ var transform = require("../../transform");
exports.ast = {
exit: function (ast, file) {
if (!transform.transformers["es6.modules"].canRun(file)) return;
if (!file.transformers["es6.modules"].canRun()) return;
useStrict.wrap(ast.program, function () {
ast.program.body = file.dynamicImports.concat(ast.program.body);