diff --git a/lib/6to5/file.js b/lib/6to5/file.js index f19ef01b87..64d2f7aad0 100644 --- a/lib/6to5/file.js +++ b/lib/6to5/file.js @@ -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"); diff --git a/lib/6to5/transformation/transformer-pass.js b/lib/6to5/transformation/transformer-pass.js new file mode 100644 index 0000000000..f1ac51d489 --- /dev/null +++ b/lib/6to5/transformation/transformer-pass.js @@ -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"); +}; diff --git a/lib/6to5/transformation/transformer.js b/lib/6to5/transformation/transformer.js index 316ca90a53..853ddf142e 100644 --- a/lib/6to5/transformation/transformer.js +++ b/lib/6to5/transformation/transformer.js @@ -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); }; diff --git a/lib/6to5/transformation/transformers/internal/module-formatter.js b/lib/6to5/transformation/transformers/internal/module-formatter.js index a5846a49d6..076c051160 100644 --- a/lib/6to5/transformation/transformers/internal/module-formatter.js +++ b/lib/6to5/transformation/transformers/internal/module-formatter.js @@ -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);