Merge pull request #5430 from loganfsmyth/opts-simplify
Simplify option and plugin pass processing
This commit is contained in:
commit
01b250a8fa
@ -45,7 +45,17 @@ export default class File extends Store {
|
||||
super();
|
||||
|
||||
this.log = new Logger(this, opts.filename || "unknown");
|
||||
this.opts = this.initOptions(opts);
|
||||
|
||||
opts = this.initOptions(opts);
|
||||
|
||||
let passes = [];
|
||||
if (opts.plugins) passes.push(opts.plugins);
|
||||
|
||||
// With "passPerPreset" enabled there may still be presets in the options.
|
||||
if (opts.presets) passes = passes.concat(opts.presets.map((preset) => preset.plugins).filter(Boolean));
|
||||
|
||||
this.pluginPasses = passes;
|
||||
this.opts = opts;
|
||||
|
||||
this.parserOpts = {
|
||||
sourceType: this.opts.sourceType,
|
||||
@ -53,22 +63,12 @@ export default class File extends Store {
|
||||
plugins: [],
|
||||
};
|
||||
|
||||
this.pluginVisitors = [];
|
||||
this.pluginPasses = [];
|
||||
|
||||
// Plugins for top-level options.
|
||||
this.buildPluginsForOptions(this.opts);
|
||||
|
||||
// If we are in the "pass per preset" mode, build
|
||||
// also plugins for each preset.
|
||||
if (this.opts.passPerPreset) {
|
||||
// All the "per preset" options are inherited from the main options.
|
||||
this.perPresetOpts = [];
|
||||
this.opts.presets.forEach((presetOpts) => {
|
||||
const perPresetOpts = Object.assign(Object.create(this.opts), presetOpts);
|
||||
this.perPresetOpts.push(perPresetOpts);
|
||||
this.buildPluginsForOptions(perPresetOpts);
|
||||
});
|
||||
for (const pluginPairs of passes) {
|
||||
for (const [ plugin ] of pluginPairs) {
|
||||
if (plugin.manipulateOptions) {
|
||||
plugin.manipulateOptions(opts, this.parserOpts, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.metadata = {
|
||||
@ -100,8 +100,7 @@ export default class File extends Store {
|
||||
|
||||
static helpers: Array<string>;
|
||||
|
||||
pluginVisitors: Array<Object>;
|
||||
pluginPasses: Array<PluginPass>;
|
||||
pluginPasses: Array<Array<[Plugin, Object]>>;
|
||||
parserOpts: BabelParserOptions;
|
||||
log: Logger;
|
||||
opts: Object;
|
||||
@ -132,7 +131,7 @@ export default class File extends Store {
|
||||
}
|
||||
|
||||
initOptions(opts) {
|
||||
opts = new OptionManager(this.log).init(opts);
|
||||
opts = this.log.wrap(() => new OptionManager().init(opts));
|
||||
|
||||
if (opts.inputSourceMap) {
|
||||
opts.sourceMaps = true;
|
||||
@ -170,31 +169,6 @@ export default class File extends Store {
|
||||
return opts;
|
||||
}
|
||||
|
||||
buildPluginsForOptions(opts) {
|
||||
if (!Array.isArray(opts.plugins)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const plugins: Array<[PluginPass, Object]> = opts.plugins.concat(INTERNAL_PLUGINS);
|
||||
const currentPluginVisitors = [];
|
||||
const currentPluginPasses = [];
|
||||
|
||||
// init plugins!
|
||||
for (const ref of plugins) {
|
||||
const [plugin, pluginOpts] = ref; // todo: fix - can't embed in loop head because of flow bug
|
||||
|
||||
currentPluginVisitors.push(plugin.visitor);
|
||||
currentPluginPasses.push(new PluginPass(this, plugin, pluginOpts));
|
||||
|
||||
if (plugin.manipulateOptions) {
|
||||
plugin.manipulateOptions(opts, this.parserOpts, this);
|
||||
}
|
||||
}
|
||||
|
||||
this.pluginVisitors.push(currentPluginVisitors);
|
||||
this.pluginPasses.push(currentPluginPasses);
|
||||
}
|
||||
|
||||
getModuleName(): ?string {
|
||||
const opts = this.opts;
|
||||
if (!opts.moduleIds) {
|
||||
@ -460,20 +434,25 @@ export default class File extends Store {
|
||||
}
|
||||
|
||||
transform(): BabelFileResult {
|
||||
// In the "pass per preset" mode, we have grouped passes.
|
||||
// Otherwise, there is only one plain pluginPasses array.
|
||||
for (let i = 0; i < this.pluginPasses.length; i++) {
|
||||
const pluginPasses = this.pluginPasses[i];
|
||||
this.call("pre", pluginPasses);
|
||||
for (const pluginPairs of this.pluginPasses) {
|
||||
const passes = [];
|
||||
const visitors = [];
|
||||
|
||||
for (const [ plugin, pluginOpts ] of pluginPairs.concat(INTERNAL_PLUGINS)) {
|
||||
const pass = new PluginPass(this, plugin, pluginOpts);
|
||||
passes.push(pass);
|
||||
visitors.push(plugin.visitor);
|
||||
}
|
||||
|
||||
this.call("pre", passes);
|
||||
this.log.debug("Start transform traverse");
|
||||
|
||||
// merge all plugin visitors into a single visitor
|
||||
const visitor = traverse.visitors.merge(this.pluginVisitors[i], pluginPasses,
|
||||
this.opts.wrapPluginVisitorMethod);
|
||||
const visitor = traverse.visitors.merge(visitors, passes, this.opts.wrapPluginVisitorMethod);
|
||||
traverse(this.ast, visitor, this.scope);
|
||||
|
||||
this.log.debug("End transform traverse");
|
||||
this.call("post", pluginPasses);
|
||||
this.call("post", passes);
|
||||
}
|
||||
|
||||
return this.generate();
|
||||
|
||||
@ -21,6 +21,15 @@ export default class Logger {
|
||||
return parts;
|
||||
}
|
||||
|
||||
wrap<T>(callback: () => T): T {
|
||||
try {
|
||||
return callback();
|
||||
} catch (e) {
|
||||
e.message = this._buildMessage(e.message);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
warn(msg: string) {
|
||||
console.warn(this._buildMessage(msg));
|
||||
}
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import type Logger from "../logger";
|
||||
import resolve from "../../../helpers/resolve";
|
||||
import json5 from "json5";
|
||||
import path from "path";
|
||||
@ -21,9 +20,9 @@ function exists(filename) {
|
||||
}
|
||||
}
|
||||
|
||||
export default function buildConfigChain(opts: Object = {}, log?: Logger) {
|
||||
export default function buildConfigChain(opts: Object = {}) {
|
||||
const filename = opts.filename;
|
||||
const builder = new ConfigChainBuilder(log);
|
||||
const builder = new ConfigChainBuilder();
|
||||
|
||||
// resolve all .babelrc files
|
||||
if (opts.babelrc !== false) {
|
||||
@ -40,10 +39,9 @@ export default function buildConfigChain(opts: Object = {}, log?: Logger) {
|
||||
}
|
||||
|
||||
class ConfigChainBuilder {
|
||||
constructor(log?: Logger) {
|
||||
constructor() {
|
||||
this.resolvedConfigs = [];
|
||||
this.configs = [];
|
||||
this.log = log;
|
||||
}
|
||||
|
||||
errorMultipleConfigs(loc1: string, loc2: string) {
|
||||
@ -183,7 +181,7 @@ class ConfigChainBuilder {
|
||||
if (extendsLoc) {
|
||||
this.addConfig(extendsLoc);
|
||||
} else {
|
||||
if (this.log) this.log.error(`Couldn't resolve extends clause of ${options.extends} in ${alias}`);
|
||||
throw new Error(`Couldn't resolve extends clause of ${options.extends} in ${alias}`);
|
||||
}
|
||||
delete options.extends;
|
||||
}
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import * as context from "../../../index";
|
||||
import type Logger from "../logger";
|
||||
import Plugin from "../../plugin";
|
||||
import * as messages from "babel-messages";
|
||||
import { normaliseOptions } from "./index";
|
||||
@ -35,15 +34,13 @@ type MergeOptions = {
|
||||
};
|
||||
|
||||
export default class OptionManager {
|
||||
constructor(log?: Logger) {
|
||||
constructor() {
|
||||
this.resolvedConfigs = [];
|
||||
this.options = OptionManager.createBareOptions();
|
||||
this.log = log;
|
||||
}
|
||||
|
||||
resolvedConfigs: Array<string>;
|
||||
options: Object;
|
||||
log: ?Logger;
|
||||
|
||||
static memoisedPlugins: Array<{
|
||||
container: Function;
|
||||
@ -158,7 +155,7 @@ export default class OptionManager {
|
||||
|
||||
//
|
||||
if (typeof rawOpts !== "object" || Array.isArray(rawOpts)) {
|
||||
this.log.error(`Invalid options type for ${alias}`, TypeError);
|
||||
throw new TypeError(`Invalid options type for ${alias}`);
|
||||
}
|
||||
|
||||
//
|
||||
@ -176,15 +173,14 @@ export default class OptionManager {
|
||||
const option = config[key];
|
||||
|
||||
// check for an unknown option
|
||||
if (!option && this.log) {
|
||||
if (!option) {
|
||||
if (removed[key]) {
|
||||
this.log.error(`Using removed Babel 5 option: ${alias}.${key} - ${removed[key].message}`,
|
||||
ReferenceError);
|
||||
throw new ReferenceError(`Using removed Babel 5 option: ${alias}.${key} - ${removed[key].message}`);
|
||||
} else {
|
||||
// eslint-disable-next-line max-len
|
||||
const unknownOptErr = `Unknown option: ${alias}.${key}. Check out http://babeljs.io/docs/usage/options/ for more information about options.`;
|
||||
|
||||
this.log.error(unknownOptErr, ReferenceError);
|
||||
throw new ReferenceError(unknownOptErr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -333,7 +329,7 @@ export default class OptionManager {
|
||||
}
|
||||
|
||||
init(opts: Object = {}): Object {
|
||||
for (const config of buildConfigChain(opts, this.log)) {
|
||||
for (const config of buildConfigChain(opts)) {
|
||||
this.mergeOptions(config);
|
||||
}
|
||||
|
||||
|
||||
@ -141,7 +141,7 @@ describe("api", function () {
|
||||
plugins: [__dirname + "/../../babel-plugin-syntax-jsx", false],
|
||||
});
|
||||
},
|
||||
/TypeError: Falsy value found in plugins/
|
||||
/TypeError: \[BABEL\] unknown: Falsy value found in plugins/
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import assert from "assert";
|
||||
import OptionManager from "../lib/transformation/file/options/option-manager";
|
||||
import Logger from "../lib/transformation/file/logger";
|
||||
import path from "path";
|
||||
|
||||
describe("option-manager", () => {
|
||||
@ -17,7 +16,7 @@ describe("option-manager", () => {
|
||||
it("throws for removed babel 5 options", () => {
|
||||
return assert.throws(
|
||||
() => {
|
||||
const opt = new OptionManager(new Logger(null, "unknown"));
|
||||
const opt = new OptionManager();
|
||||
opt.init({
|
||||
"randomOption": true,
|
||||
});
|
||||
@ -29,7 +28,7 @@ describe("option-manager", () => {
|
||||
it("throws for removed babel 5 options", () => {
|
||||
return assert.throws(
|
||||
() => {
|
||||
const opt = new OptionManager(new Logger(null, "unknown"));
|
||||
const opt = new OptionManager();
|
||||
opt.init({
|
||||
"auxiliaryComment": true,
|
||||
"blacklist": true,
|
||||
@ -43,7 +42,7 @@ describe("option-manager", () => {
|
||||
it("throws for resolved but erroring preset", () => {
|
||||
return assert.throws(
|
||||
() => {
|
||||
const opt = new OptionManager(new Logger(null, "unknown"));
|
||||
const opt = new OptionManager();
|
||||
opt.init({
|
||||
"presets": [path.join(__dirname, "fixtures/option-manager/not-a-preset")],
|
||||
});
|
||||
@ -56,7 +55,7 @@ describe("option-manager", () => {
|
||||
describe("presets", function () {
|
||||
function presetTest(name) {
|
||||
it(name, function () {
|
||||
const opt = new OptionManager(new Logger(null, "unknown"));
|
||||
const opt = new OptionManager();
|
||||
const options = opt.init({
|
||||
"presets": [path.join(__dirname, "fixtures/option-manager/presets", name)],
|
||||
});
|
||||
@ -68,7 +67,7 @@ describe("option-manager", () => {
|
||||
|
||||
function presetThrowsTest(name, msg) {
|
||||
it(name, function () {
|
||||
const opt = new OptionManager(new Logger(null, "unknown"));
|
||||
const opt = new OptionManager();
|
||||
assert.throws(() => opt.init({
|
||||
"presets": [path.join(__dirname, "fixtures/option-manager/presets", name)],
|
||||
}), msg);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user