abstract plugin initialisation to a plugin manager
This commit is contained in:
parent
04766b13f5
commit
9cb16711dd
@ -26,7 +26,15 @@ export const MESSAGES = {
|
||||
traverseNeedsParent: "Must pass a scope and parentPath unless traversing a Program/File got a $1 node",
|
||||
traverseVerifyRootFunction: "You passed `traverse()` a function when it expected a visitor object, are you sure you didn't mean `{ enter: Function }`?",
|
||||
traverseVerifyVisitorFunction: "Hey! You passed \`traverse()\` a visitor object with the key $1 that's a straight up `Function` instead of `{ enter: Function }`. You need to normalise it with `traverse.explode(visitor)`.",
|
||||
traverseVerifyVisitorProperty: "You passed `traverse()` a visitor object with the property $1 that has the invalid property $2"
|
||||
traverseVerifyVisitorProperty: "You passed `traverse()` a visitor object with the property $1 that has the invalid property $2",
|
||||
|
||||
pluginIllegalKind: "Illegal kind $1 for plugin $2",
|
||||
pluginIllegalPosition: "Illegal position $1 for plugin $2",
|
||||
pluginKeyCollision: "The plugin $1 collides with another of the same name",
|
||||
pluginNotTransformer: "The plugin $1 didn't export a Transformer instance",
|
||||
pluginUnknown: "Unknown plugin $1",
|
||||
|
||||
transformerNotFile: "Transformer $1 is resolving to a different Babel version to what is doing the actual transformation..."
|
||||
};
|
||||
|
||||
export function get(key: String, ...args) {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import convertSourceMap from "convert-source-map";
|
||||
import * as optionParsers from "./option-parsers";
|
||||
import PluginManager from "./plugin-manager";
|
||||
import shebangRegex from "shebang-regex";
|
||||
import TraversalPath from "../../traversal/path";
|
||||
import isFunction from "lodash/lang/isFunction";
|
||||
@ -18,6 +19,7 @@ import Scope from "../../traversal/scope";
|
||||
import slash from "slash";
|
||||
import clone from "lodash/lang/clone";
|
||||
import * as util from "../../util";
|
||||
import * as api from "../../api/node";
|
||||
import path from "path";
|
||||
import each from "lodash/collection/each";
|
||||
import * as t from "../../types";
|
||||
@ -217,8 +219,9 @@ export default class File {
|
||||
// init plugins!
|
||||
var beforePlugins = [];
|
||||
var afterPlugins = [];
|
||||
var pluginManager = new PluginManager(this.transformers, beforePlugins, afterPlugins);
|
||||
for (var i = 0; i < file.opts.plugins.length; i++) {
|
||||
this.addPlugin(file.opts.plugins[i], beforePlugins, afterPlugins);
|
||||
pluginManager.add(file.opts.plugins[i]);
|
||||
}
|
||||
stack = beforePlugins.concat(stack, afterPlugins);
|
||||
|
||||
@ -241,60 +244,6 @@ export default class File {
|
||||
return new ModuleFormatter(this);
|
||||
}
|
||||
|
||||
addPlugin(name, before, after) {
|
||||
var position = "before";
|
||||
var plugin;
|
||||
|
||||
if (name) {
|
||||
if (typeof name === "object" && name.transformer) {
|
||||
plugin = name.transformer;
|
||||
position = name.position || position;
|
||||
} else if (typeof name === "string") {
|
||||
// this is a plugin in the form of "foobar" or "foobar:after"
|
||||
// where the optional colon is the delimiter for plugin position in the transformer stack
|
||||
|
||||
[name, position = "before"] = name.split(":");
|
||||
|
||||
var loc = util.resolveRelative(name) || util.resolveRelative(`babel-plugin-${name}`);
|
||||
if (loc) {
|
||||
plugin = require(loc)
|
||||
} else {
|
||||
throw new ReferenceError(`Unknown plugin ${JSON.stringify(name)}`);
|
||||
}
|
||||
} else {
|
||||
// not a string so we'll just assume that it's a direct Transformer instance, if not then
|
||||
// the checks later on will complain
|
||||
plugin = name;
|
||||
}
|
||||
} else {
|
||||
throw new TypeError(`Ilegal kind ${typeof name} for plugin name ${JSON.stringify(name)}`);
|
||||
}
|
||||
|
||||
// validate position
|
||||
if (position !== "before" && position !== "after") {
|
||||
throw new TypeError(`Plugin ${JSON.stringify(name)} has an illegal position of ${JSON.stringify(position)}`);
|
||||
}
|
||||
|
||||
// validate transformer key
|
||||
var key = plugin.key;
|
||||
if (this.transformers[key]) {
|
||||
throw new ReferenceError(`The key for plugin ${JSON.stringify(name)} of ${key} collides with an existing plugin`);
|
||||
}
|
||||
|
||||
// validate Transformer instance
|
||||
if (!plugin.buildPass || plugin.constructor.name !== "Transformer") {
|
||||
throw new TypeError(`Plugin ${JSON.stringify(name)} didn't export a default Transformer instance`);
|
||||
}
|
||||
|
||||
// build!
|
||||
var pass = this.transformers[key] = plugin.buildPass(this);
|
||||
if (pass.canTransform()) {
|
||||
var stack = before;
|
||||
if (position === "after") stack = after;
|
||||
stack.push(pass);
|
||||
}
|
||||
}
|
||||
|
||||
parseInputSourceMap(code: string) {
|
||||
var opts = this.opts;
|
||||
|
||||
|
||||
99
src/babel/transformation/file/plugin-manager.js
Normal file
99
src/babel/transformation/file/plugin-manager.js
Normal file
@ -0,0 +1,99 @@
|
||||
import * as messages from "../../messages";
|
||||
|
||||
export default class PluginManager {
|
||||
static memoisedPlugins = [];
|
||||
|
||||
static memoisePluginContainer(fn) {
|
||||
for (var i = 0; i < PluginManager.memoisedPlugins.length; i++) {
|
||||
var plugin = PluginManager.memoisedPlugins[i];
|
||||
if (plugin.container === fn) return plugin.transformer;
|
||||
}
|
||||
|
||||
var transformer = fn(node);
|
||||
PluginManager.memoisedPlugins.push({
|
||||
container: fn,
|
||||
transformer: transformer
|
||||
});
|
||||
return transformer;
|
||||
}
|
||||
|
||||
constructor(transformers, before, after) {
|
||||
this.transformers = transformers;
|
||||
this.before = before;
|
||||
this.after = after;
|
||||
}
|
||||
|
||||
subnormaliseString(name) {
|
||||
// this is a plugin in the form of "foobar" or "foobar:after"
|
||||
// where the optional colon is the delimiter for plugin position in the transformer stack
|
||||
|
||||
var [name, position] = name.split(":");
|
||||
|
||||
var loc = util.resolveRelative(name) || util.resolveRelative(`babel-plugin-${name}`);
|
||||
if (loc) {
|
||||
return {
|
||||
position: position,
|
||||
plugin: require(loc)
|
||||
};
|
||||
} else {
|
||||
throw new ReferenceError(messages.get("pluginUnknown", name));
|
||||
}
|
||||
}
|
||||
|
||||
validate(plugin) {
|
||||
// validate transformer key
|
||||
var key = plugin.key;
|
||||
if (this.transformers[key]) {
|
||||
throw new ReferenceError(messages.get("pluginKeyCollision", key));
|
||||
}
|
||||
|
||||
// validate Transformer instance
|
||||
if (!plugin.buildPass || plugin.constructor.name !== "Transformer") {
|
||||
throw new TypeError(messages.get("pluginNotTransformer", name));
|
||||
}
|
||||
}
|
||||
|
||||
add(name) {
|
||||
var position;
|
||||
var plugin;
|
||||
|
||||
if (name) {
|
||||
if (typeof name === "object" && name.transformer) {
|
||||
({ plugin: name, position } = name);
|
||||
} else if (typeof name !== "string") {
|
||||
// not a string so we'll just assume that it's a direct Transformer instance, if not then
|
||||
// the checks later on will complain
|
||||
plugin = name;
|
||||
}
|
||||
|
||||
if (typeof name === "string") {
|
||||
({ plugin, position } = this.subnormaliseString(name));
|
||||
}
|
||||
} else {
|
||||
throw new TypeError(messages.get("pluginIllegalKind", typeof name, name));
|
||||
}
|
||||
|
||||
// default position
|
||||
position = position || "before";
|
||||
|
||||
// validate position
|
||||
if (position !== "before" && position !== "after") {
|
||||
throw new TypeError(messages.get("pluginIllegalPosition", position, name));
|
||||
}
|
||||
|
||||
// allow plugin containers to be specified so they don't have to manually require
|
||||
if (typeof plugin === "function") {
|
||||
plugin = PluginManager.memoisePluginContainer(plugin);
|
||||
}
|
||||
|
||||
//
|
||||
this.validate(plugin);
|
||||
|
||||
// build!
|
||||
var pass = this.transformers[key] = plugin.buildPass(this);
|
||||
if (pass.canTransform()) {
|
||||
var stack = position === "before" ? this.before : this.after;
|
||||
stack.push(pass);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -87,7 +87,7 @@ export default class Transformer {
|
||||
buildPass(file: File): TransformerPass {
|
||||
// validate Transformer instance
|
||||
if (!(file instanceof File)) {
|
||||
throw new TypeError(`Transformer ${this.key} is resolving to a different Babel version to what is doing the actual transformation...`);
|
||||
throw new TypeError(messages.get("transformerNotFile", this.key));
|
||||
}
|
||||
|
||||
return new TransformerPass(file, this);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user