diff --git a/packages/babel-core/src/config/build-config-chain.js b/packages/babel-core/src/config/build-config-chain.js index ab253cf8dc..27d6ac99c0 100644 --- a/packages/babel-core/src/config/build-config-chain.js +++ b/packages/babel-core/src/config/build-config-chain.js @@ -39,16 +39,17 @@ type ConfigPart = }; export default function buildConfigChain( + cwd: string, opts: ValidatedOptions, envName: string, ): Array | null { - const filename = opts.filename ? path.resolve(opts.filename) : null; + const filename = opts.filename ? path.resolve(cwd, opts.filename) : null; const builder = new ConfigChainBuilder( filename ? new LoadedFile(filename) : null, ); try { - builder.mergeConfigArguments(opts, process.cwd(), envName); + builder.mergeConfigArguments(opts, cwd, envName); // resolve all .babelrc files if (opts.babelrc !== false && filename) { diff --git a/packages/babel-core/src/config/option-manager.js b/packages/babel-core/src/config/option-manager.js index d7c7c958c5..42c1ac4e1f 100644 --- a/packages/babel-core/src/config/option-manager.js +++ b/packages/babel-core/src/config/option-manager.js @@ -1,5 +1,6 @@ // @flow +import path from "path"; import * as context from "../index"; import Plugin, { validatePluginObject } from "./plugin"; import merge from "lodash/merge"; @@ -45,36 +46,29 @@ class OptionManager { * - `loc` is used to point to the original config. * - `dirname` is used to resolve plugins relative to it. */ - - mergeOptions(config: MergeOptions, pass?: Array, envName: string) { + mergeOptions(config: MergeOptions, pass: Array, envName: string) { const result = loadConfig(config); const plugins = result.plugins.map(descriptor => loadPluginDescriptor(descriptor, envName), ); - const presets = result.presets.map(descriptor => - loadPresetDescriptor(descriptor, envName), - ); - - const passPerPreset = config.options.passPerPreset; - pass = pass || this.passes[0]; + const presets = result.presets.map(descriptor => ({ + pass: descriptor.ownPass ? [] : pass, + preset: loadPresetDescriptor(descriptor, envName), + })); // resolve presets if (presets.length > 0) { - let presetPasses = null; - if (passPerPreset) { - presetPasses = presets.map(() => []); - // The passes are created in the same order as the preset list, but are inserted before any - // existing additional passes. - this.passes.splice(1, 0, ...presetPasses); - } + // The passes are created in the same order as the preset list, but are inserted before any + // existing additional passes. + this.passes.splice( + 1, + 0, + ...presets.map(o => o.pass).filter(p => p !== pass), + ); - presets.forEach((presetConfig, i) => { - this.mergeOptions( - presetConfig, - presetPasses ? presetPasses[i] : pass, - envName, - ); + presets.forEach(({ preset, pass }) => { + this.mergeOptions(preset, pass, envName); }); } @@ -103,14 +97,15 @@ class OptionManager { init(inputOpts: {}) { const args = validate("arguments", inputOpts); - const { envName = getEnv() } = args; + const { envName = getEnv(), cwd = "." } = args; + const absoluteCwd = path.resolve(cwd); - const configChain = buildConfigChain(args, envName); + const configChain = buildConfigChain(absoluteCwd, args, envName); if (!configChain) return null; try { for (const config of configChain) { - this.mergeOptions(config, undefined, envName); + this.mergeOptions(config, this.passes[0], envName); } } catch (e) { // There are a few case where thrown errors will try to annotate themselves multiple times, so @@ -134,6 +129,7 @@ class OptionManager { .map(plugins => ({ plugins })); opts.passPerPreset = opts.presets.length > 0; opts.envName = envName; + opts.cwd = absoluteCwd; return { options: opts, @@ -147,6 +143,7 @@ type BasicDescriptor = { options: {} | void, dirname: string, alias: string, + ownPass?: boolean, }; type LoadedDescriptor = { @@ -177,6 +174,7 @@ const loadConfig = makeWeakCache((config: MergeOptions): { createDescriptor(preset, loadPreset, config.dirname, { index, alias: config.alias, + ownPass: config.options.passPerPreset, }), ); @@ -320,9 +318,11 @@ function createDescriptor( { index, alias, + ownPass, }: { index: number, alias: string, + ownPass?: boolean, }, ): BasicDescriptor { let options; @@ -363,18 +363,12 @@ function createDescriptor( ); } - if (options != null && typeof options !== "object") { - throw new Error( - "Plugin/Preset options must be an object, null, or undefined", - ); - } - options = options || undefined; - return { alias: filepath || `${alias}$${index}`, value, options, dirname, + ownPass, }; } diff --git a/packages/babel-core/src/config/options.js b/packages/babel-core/src/config/options.js index 5ca278b14b..9aec95dfa8 100644 --- a/packages/babel-core/src/config/options.js +++ b/packages/babel-core/src/config/options.js @@ -17,6 +17,7 @@ import { } from "./option-assertions"; const ROOT_VALIDATORS: ValidatorSet = { + cwd: (assertString: Validator<$PropertyType>), filename: (assertString: Validator< $PropertyType, >), @@ -128,6 +129,7 @@ const COMMON_VALIDATORS: ValidatorSet = { export type InputOptions = ValidatedOptions; export type ValidatedOptions = { + cwd?: string, filename?: string, filenameRelative?: string, babelrc?: boolean, @@ -206,6 +208,9 @@ export function validate(type: OptionsType, opts: {}): ValidatedOptions { if (type !== "arguments" && ROOT_VALIDATORS[key]) { throw new Error(`.${key} is only allowed in root programmatic options`); } + if (type === "env" && key === "env") { + throw new Error(`.${key} is not allowed inside another env block`); + } const validator = COMMON_VALIDATORS[key] || diff --git a/packages/babel-core/test/api.js b/packages/babel-core/test/api.js index cad0308862..215a8960f1 100644 --- a/packages/babel-core/test/api.js +++ b/packages/babel-core/test/api.js @@ -296,12 +296,6 @@ describe("api", function() { development: { passPerPreset: true, presets: [pushPreset("argthree"), pushPreset("argfour")], - env: { - development: { - passPerPreset: true, - presets: [pushPreset("argfive"), pushPreset("argsix")], - }, - }, }, }, }); @@ -327,8 +321,6 @@ describe("api", function() { "fourteen;", "fifteen;", "sixteen;", - "argfive;", - "argsix;", "argthree;", "argfour;", "seven;", diff --git a/packages/babel-core/test/config-chain.js b/packages/babel-core/test/config-chain.js index d4bb482212..4b4ea20ff0 100644 --- a/packages/babel-core/test/config-chain.js +++ b/packages/babel-core/test/config-chain.js @@ -1,10 +1,14 @@ import assert from "assert"; import fs from "fs"; import path from "path"; -import buildConfigChain from "../lib/config/build-config-chain"; +import buildConfigChainFn from "../lib/config/build-config-chain"; const DEFAULT_ENV = "development"; +function buildConfigChain(opts, envName) { + return buildConfigChainFn(process.cwd(), opts, envName); +} + function fixture() { const args = [__dirname, "fixtures", "config"]; for (let i = 0; i < arguments.length; i++) { diff --git a/packages/babel-preset-es2015/test/fixtures/traceur/options.json b/packages/babel-preset-es2015/test/fixtures/traceur/options.json index ea93819975..02c0b709d1 100644 --- a/packages/babel-preset-es2015/test/fixtures/traceur/options.json +++ b/packages/babel-preset-es2015/test/fixtures/traceur/options.json @@ -1,7 +1,6 @@ { "plugins": [ "transform-exponentiation-operator", - "transform-regenerator", "transform-template-literals", "transform-literals", "transform-arrow-functions",