Add wrapPluginVisitorMethod option to allow introspection and metrics tracking of plugins (#3659)
This commit is contained in:
parent
ea69362249
commit
07b3dc18a0
@ -442,7 +442,11 @@ export default class File extends Store {
|
||||
const pluginPasses = this.pluginPasses[i];
|
||||
this.call("pre", pluginPasses);
|
||||
this.log.debug("Start transform traverse");
|
||||
traverse(this.ast, traverse.visitors.merge(this.pluginVisitors[i], pluginPasses), this.scope);
|
||||
|
||||
// merge all plugin visitors into a single visitor
|
||||
let visitor = traverse.visitors.merge(this.pluginVisitors[i], pluginPasses, this.opts.wrapPluginVisitorMethod);
|
||||
traverse(this.ast, visitor, this.scope);
|
||||
|
||||
this.log.debug("End transform traverse");
|
||||
this.call("post", pluginPasses);
|
||||
}
|
||||
|
||||
@ -102,6 +102,11 @@ module.exports = {
|
||||
description: "optional callback to control whether a comment should be inserted, when this is used the comments option is ignored"
|
||||
},
|
||||
|
||||
wrapPluginVisitorMethod: {
|
||||
hidden: true,
|
||||
description: "optional callback to wrap all visitor methods"
|
||||
},
|
||||
|
||||
compact: {
|
||||
type: "booleanString",
|
||||
default: "auto",
|
||||
|
||||
@ -13,6 +13,8 @@ export default new Plugin({
|
||||
* - 3 We want this to be at the **very** top
|
||||
*/
|
||||
|
||||
name: "internal.blockHoist",
|
||||
|
||||
visitor: {
|
||||
Block: {
|
||||
exit({ node }) {
|
||||
|
||||
@ -16,6 +16,8 @@ const superVisitor = {
|
||||
};
|
||||
|
||||
export default new Plugin({
|
||||
name: "internal.shadowFunctions",
|
||||
|
||||
visitor: {
|
||||
ThisExpression(path) {
|
||||
remap(path, "this");
|
||||
|
||||
@ -1,27 +1,21 @@
|
||||
import type Plugin from "./plugin";
|
||||
import Store from "../store";
|
||||
import traverse from "babel-traverse";
|
||||
import File from "./file";
|
||||
|
||||
export default class PluginPass extends Store {
|
||||
constructor(file: File, plugin: Plugin, options: Object = {}) {
|
||||
super();
|
||||
this.plugin = plugin;
|
||||
this.key = plugin.key;
|
||||
this.file = file;
|
||||
this.opts = options;
|
||||
}
|
||||
|
||||
key: string;
|
||||
plugin: Plugin;
|
||||
file: File;
|
||||
opts: Object;
|
||||
|
||||
transform() {
|
||||
let file = this.file;
|
||||
file.log.debug(`Start transformer ${this.key}`);
|
||||
traverse(file.ast, this.plugin.visitor, file.scope, file);
|
||||
file.log.debug(`Finish transformer ${this.key}`);
|
||||
}
|
||||
|
||||
addHelper(...args) {
|
||||
return this.file.addHelper(...args);
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ export default class Plugin extends Store {
|
||||
|
||||
this.initialized = false;
|
||||
this.raw = assign({}, plugin);
|
||||
this.key = key;
|
||||
this.key = this.take("name") || key;
|
||||
|
||||
this.manipulateOptions = this.take("manipulateOptions");
|
||||
this.post = this.take("post");
|
||||
|
||||
@ -76,6 +76,38 @@ suite("api", function () {
|
||||
});
|
||||
});
|
||||
|
||||
test("option wrapPluginVisitorMethod", function () {
|
||||
var calledRaw = 0;
|
||||
var calledIntercept = 0;
|
||||
|
||||
babel.transform("function foo() { bar(foobar); }", {
|
||||
wrapPluginVisitorMethod: function (pluginAlias, visitorType, callback) {
|
||||
if (pluginAlias !== "foobar") {
|
||||
return callback;
|
||||
}
|
||||
|
||||
assert.equal(visitorType, "enter");
|
||||
|
||||
return function () {
|
||||
calledIntercept++;
|
||||
return callback.apply(this, arguments);
|
||||
};
|
||||
},
|
||||
|
||||
plugins: [new Plugin({
|
||||
name: "foobar",
|
||||
visitor: {
|
||||
"Program|Identifier": function () {
|
||||
calledRaw++;
|
||||
}
|
||||
}
|
||||
})]
|
||||
});
|
||||
|
||||
assert.equal(calledRaw, 4);
|
||||
assert.equal(calledIntercept, 4);
|
||||
});
|
||||
|
||||
test("pass per preset", function () {
|
||||
var aliasBaseType = null;
|
||||
|
||||
|
||||
@ -162,7 +162,7 @@ function validateVisitorMethods(path, val) {
|
||||
}
|
||||
}
|
||||
|
||||
export function merge(visitors: Array, states: Array = []) {
|
||||
export function merge(visitors: Array, states: Array = [], wrapper?: ?Function) {
|
||||
let rootVisitor = {};
|
||||
|
||||
for (let i = 0; i < visitors.length; i++) {
|
||||
@ -174,8 +174,10 @@ export function merge(visitors: Array, states: Array = []) {
|
||||
for (let type in visitor) {
|
||||
let visitorType = visitor[type];
|
||||
|
||||
// if we have state then overload the callbacks to take it
|
||||
if (state) visitorType = wrapWithState(visitorType, state);
|
||||
// if we have state or wrapper then overload the callbacks to take it
|
||||
if (state || wrapper) {
|
||||
visitorType = wrapWithStateOrWrapper(visitorType, state, wrapper);
|
||||
}
|
||||
|
||||
let nodeVisitor = rootVisitor[type] = rootVisitor[type] || {};
|
||||
mergePair(nodeVisitor, visitorType);
|
||||
@ -185,7 +187,7 @@ export function merge(visitors: Array, states: Array = []) {
|
||||
return rootVisitor;
|
||||
}
|
||||
|
||||
function wrapWithState(oldVisitor, state) {
|
||||
function wrapWithStateOrWrapper(oldVisitor, state, wrapper: ?Function) {
|
||||
let newVisitor = {};
|
||||
|
||||
for (let key in oldVisitor) {
|
||||
@ -195,10 +197,18 @@ function wrapWithState(oldVisitor, state) {
|
||||
if (!Array.isArray(fns)) continue;
|
||||
|
||||
fns = fns.map(function (fn) {
|
||||
let newFn = function (path) {
|
||||
return fn.call(state, path, state);
|
||||
};
|
||||
newFn.toString = () => fn.toString();
|
||||
let newFn = fn;
|
||||
|
||||
if (state) {
|
||||
newFn = function (path) {
|
||||
return fn.call(state, path, state);
|
||||
};
|
||||
}
|
||||
|
||||
if (wrapper) {
|
||||
newFn = wrapper(state.key, key, newFn);
|
||||
}
|
||||
|
||||
return newFn;
|
||||
});
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user