Move .inherits handling to OptionManager.
This commit is contained in:
@@ -7,6 +7,8 @@ import merge from "./helpers/merge";
|
||||
import removed from "./removed";
|
||||
import buildConfigChain from "./build-config-chain";
|
||||
import path from "path";
|
||||
import traverse from "babel-traverse";
|
||||
import clone from "lodash/clone";
|
||||
|
||||
import { loadPlugin, loadPreset, loadParser, loadGenerator } from "./loading/files";
|
||||
|
||||
@@ -74,6 +76,15 @@ const optionNames = new Set([
|
||||
"generatorOpts",
|
||||
]);
|
||||
|
||||
const ALLOWED_PLUGIN_KEYS = new Set([
|
||||
"name",
|
||||
"manipulateOptions",
|
||||
"pre",
|
||||
"post",
|
||||
"visitor",
|
||||
"inherits",
|
||||
]);
|
||||
|
||||
export default class OptionManager {
|
||||
constructor() {
|
||||
this.options = OptionManager.createBareOptions();
|
||||
@@ -99,16 +110,51 @@ export default class OptionManager {
|
||||
obj = fn;
|
||||
}
|
||||
|
||||
if (typeof obj === "object") {
|
||||
const plugin = new Plugin(obj, alias);
|
||||
OptionManager.memoisedPlugins.push({
|
||||
container: fn,
|
||||
plugin: plugin,
|
||||
});
|
||||
return plugin;
|
||||
} else {
|
||||
if (typeof obj !== "object") {
|
||||
throw new TypeError(messages.get("pluginNotObject", loc, i, typeof obj) + loc + i);
|
||||
}
|
||||
Object.keys(obj).forEach((key) => {
|
||||
if (!ALLOWED_PLUGIN_KEYS.has(key)) {
|
||||
throw new Error(messages.get("pluginInvalidProperty", loc, i, key));
|
||||
}
|
||||
});
|
||||
if (obj.visitor && (obj.visitor.enter || obj.visitor.exit)) {
|
||||
throw new Error("Plugins aren't allowed to specify catch-all enter/exit handlers. " +
|
||||
"Please target individual nodes.");
|
||||
}
|
||||
|
||||
obj = Object.assign({}, obj, {
|
||||
visitor: clone(obj.visitor || {}),
|
||||
});
|
||||
|
||||
traverse.explode(obj.visitor);
|
||||
|
||||
if (obj.inherits) {
|
||||
const inherited = OptionManager.normalisePlugin(obj.inherits, loc, "inherits");
|
||||
|
||||
obj.pre = OptionManager.chain(inherited.pre, obj.pre);
|
||||
obj.post = OptionManager.chain(inherited.post, obj.post);
|
||||
obj.manipulateOptions = OptionManager.chain(inherited.manipulateOptions, obj.manipulateOptions);
|
||||
obj.visitor = traverse.visitors.merge([inherited.visitor, obj.visitor]);
|
||||
}
|
||||
|
||||
const plugin = new Plugin(obj, alias);
|
||||
OptionManager.memoisedPlugins.push({
|
||||
container: fn,
|
||||
plugin: plugin,
|
||||
});
|
||||
return plugin;
|
||||
}
|
||||
|
||||
static chain(a, b) {
|
||||
const fns = [a, b].filter(Boolean);
|
||||
if (fns.length <= 1) return fns[0];
|
||||
|
||||
return function(...args) {
|
||||
for (const fn of fns) {
|
||||
fn.apply(this, args);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static createBareOptions() {
|
||||
@@ -137,8 +183,6 @@ export default class OptionManager {
|
||||
}
|
||||
}
|
||||
|
||||
plugin.init(loc, i);
|
||||
|
||||
return plugin;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,90 +1,16 @@
|
||||
import OptionManager from "./option-manager";
|
||||
import * as messages from "babel-messages";
|
||||
import traverse from "babel-traverse";
|
||||
import clone from "lodash/clone";
|
||||
|
||||
const GLOBAL_VISITOR_PROPS = ["enter", "exit"];
|
||||
|
||||
export default class Plugin {
|
||||
constructor(plugin: Object, key?: string) {
|
||||
this.initialized = false;
|
||||
this.raw = Object.assign({}, plugin);
|
||||
this.key = this.take("name") || key;
|
||||
this.key = plugin.name || key;
|
||||
|
||||
this.manipulateOptions = this.take("manipulateOptions");
|
||||
this.post = this.take("post");
|
||||
this.pre = this.take("pre");
|
||||
this.visitor = this.normaliseVisitor(clone(this.take("visitor")) || {});
|
||||
this.manipulateOptions = plugin.manipulateOptions;
|
||||
this.post = plugin.post;
|
||||
this.pre = plugin.pre;
|
||||
this.visitor = plugin.visitor;
|
||||
}
|
||||
|
||||
initialized: boolean;
|
||||
raw: Object;
|
||||
key: ?string;
|
||||
manipulateOptions: ?Function;
|
||||
post: ?Function;
|
||||
pre: ?Function;
|
||||
visitor: Object;
|
||||
|
||||
take(key) {
|
||||
const val = this.raw[key];
|
||||
delete this.raw[key];
|
||||
return val;
|
||||
}
|
||||
|
||||
chain(target, key) {
|
||||
if (!target[key]) return this[key];
|
||||
if (!this[key]) return target[key];
|
||||
|
||||
const fns: Array<?Function> = [target[key], this[key]];
|
||||
|
||||
return function (...args) {
|
||||
let val;
|
||||
for (const fn of fns) {
|
||||
if (fn) {
|
||||
const ret = fn.apply(this, args);
|
||||
if (ret != null) val = ret;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
};
|
||||
}
|
||||
|
||||
maybeInherit(loc: string) {
|
||||
let inherits = this.take("inherits");
|
||||
if (!inherits) return;
|
||||
|
||||
inherits = OptionManager.normalisePlugin(inherits, loc, "inherits");
|
||||
|
||||
this.manipulateOptions = this.chain(inherits, "manipulateOptions");
|
||||
this.post = this.chain(inherits, "post");
|
||||
this.pre = this.chain(inherits, "pre");
|
||||
this.visitor = traverse.visitors.merge([inherits.visitor, this.visitor]);
|
||||
}
|
||||
|
||||
/**
|
||||
* We lazy initialise parts of a plugin that rely on contextual information such as
|
||||
* position on disk and how it was specified.
|
||||
*/
|
||||
|
||||
init(loc: string, i: number) {
|
||||
if (this.initialized) return;
|
||||
this.initialized = true;
|
||||
|
||||
this.maybeInherit(loc);
|
||||
|
||||
for (const key in this.raw) {
|
||||
throw new Error(messages.get("pluginInvalidProperty", loc, i, key));
|
||||
}
|
||||
}
|
||||
|
||||
normaliseVisitor(visitor: Object): Object {
|
||||
for (const key of GLOBAL_VISITOR_PROPS) {
|
||||
if (visitor[key]) {
|
||||
throw new Error("Plugins aren't allowed to specify catch-all enter/exit handlers. " +
|
||||
"Please target individual nodes.");
|
||||
}
|
||||
}
|
||||
|
||||
traverse.explode(visitor);
|
||||
return visitor;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user