439 lines
14 KiB
JavaScript
439 lines
14 KiB
JavaScript
|
"use strict";
|
||
|
|
||
|
Object.defineProperty(exports, "__esModule", {
|
||
|
value: true
|
||
|
});
|
||
|
exports.buildPresetChain = buildPresetChain;
|
||
|
exports.buildRootChain = buildRootChain;
|
||
|
exports.buildPresetChainWalker = void 0;
|
||
|
|
||
|
function _path() {
|
||
|
const data = _interopRequireDefault(require("path"));
|
||
|
|
||
|
_path = function () {
|
||
|
return data;
|
||
|
};
|
||
|
|
||
|
return data;
|
||
|
}
|
||
|
|
||
|
function _debug() {
|
||
|
const data = _interopRequireDefault(require("debug"));
|
||
|
|
||
|
_debug = function () {
|
||
|
return data;
|
||
|
};
|
||
|
|
||
|
return data;
|
||
|
}
|
||
|
|
||
|
var _options = require("./validation/options");
|
||
|
|
||
|
var _patternToRegex = _interopRequireDefault(require("./pattern-to-regex"));
|
||
|
|
||
|
var _files = require("./files");
|
||
|
|
||
|
var _caching = require("./caching");
|
||
|
|
||
|
var _configDescriptors = require("./config-descriptors");
|
||
|
|
||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
|
||
|
const debug = (0, _debug().default)("babel:config:config-chain");
|
||
|
|
||
|
function buildPresetChain(arg, context) {
|
||
|
const chain = buildPresetChainWalker(arg, context);
|
||
|
if (!chain) return null;
|
||
|
return {
|
||
|
plugins: dedupDescriptors(chain.plugins),
|
||
|
presets: dedupDescriptors(chain.presets),
|
||
|
options: chain.options.map(o => normalizeOptions(o))
|
||
|
};
|
||
|
}
|
||
|
|
||
|
const buildPresetChainWalker = makeChainWalker({
|
||
|
init: arg => arg,
|
||
|
root: preset => loadPresetDescriptors(preset),
|
||
|
env: (preset, envName) => loadPresetEnvDescriptors(preset)(envName),
|
||
|
overrides: (preset, index) => loadPresetOverridesDescriptors(preset)(index),
|
||
|
overridesEnv: (preset, index, envName) => loadPresetOverridesEnvDescriptors(preset)(index)(envName)
|
||
|
});
|
||
|
exports.buildPresetChainWalker = buildPresetChainWalker;
|
||
|
const loadPresetDescriptors = (0, _caching.makeWeakCache)(preset => buildRootDescriptors(preset, preset.alias, _configDescriptors.createUncachedDescriptors));
|
||
|
const loadPresetEnvDescriptors = (0, _caching.makeWeakCache)(preset => (0, _caching.makeStrongCache)(envName => buildEnvDescriptors(preset, preset.alias, _configDescriptors.createUncachedDescriptors, envName)));
|
||
|
const loadPresetOverridesDescriptors = (0, _caching.makeWeakCache)(preset => (0, _caching.makeStrongCache)(index => buildOverrideDescriptors(preset, preset.alias, _configDescriptors.createUncachedDescriptors, index)));
|
||
|
const loadPresetOverridesEnvDescriptors = (0, _caching.makeWeakCache)(preset => (0, _caching.makeStrongCache)(index => (0, _caching.makeStrongCache)(envName => buildOverrideEnvDescriptors(preset, preset.alias, _configDescriptors.createUncachedDescriptors, index, envName))));
|
||
|
|
||
|
function buildRootChain(opts, context) {
|
||
|
const programmaticChain = loadProgrammaticChain({
|
||
|
options: opts,
|
||
|
dirname: context.cwd
|
||
|
}, context);
|
||
|
if (!programmaticChain) return null;
|
||
|
let configFile;
|
||
|
|
||
|
if (typeof opts.configFile === "string") {
|
||
|
configFile = (0, _files.loadConfig)(opts.configFile, context.cwd, context.envName, context.caller);
|
||
|
} else if (opts.configFile !== false) {
|
||
|
configFile = (0, _files.findRootConfig)(context.root, context.envName, context.caller);
|
||
|
}
|
||
|
|
||
|
let {
|
||
|
babelrc,
|
||
|
babelrcRoots
|
||
|
} = opts;
|
||
|
let babelrcRootsDirectory = context.cwd;
|
||
|
const configFileChain = emptyChain();
|
||
|
|
||
|
if (configFile) {
|
||
|
const validatedFile = validateConfigFile(configFile);
|
||
|
const result = loadFileChain(validatedFile, context);
|
||
|
if (!result) return null;
|
||
|
|
||
|
if (babelrc === undefined) {
|
||
|
babelrc = validatedFile.options.babelrc;
|
||
|
}
|
||
|
|
||
|
if (babelrcRoots === undefined) {
|
||
|
babelrcRootsDirectory = validatedFile.dirname;
|
||
|
babelrcRoots = validatedFile.options.babelrcRoots;
|
||
|
}
|
||
|
|
||
|
mergeChain(configFileChain, result);
|
||
|
}
|
||
|
|
||
|
const pkgData = typeof context.filename === "string" ? (0, _files.findPackageData)(context.filename) : null;
|
||
|
let ignoreFile, babelrcFile;
|
||
|
const fileChain = emptyChain();
|
||
|
|
||
|
if ((babelrc === true || babelrc === undefined) && pkgData && babelrcLoadEnabled(context, pkgData, babelrcRoots, babelrcRootsDirectory)) {
|
||
|
({
|
||
|
ignore: ignoreFile,
|
||
|
config: babelrcFile
|
||
|
} = (0, _files.findRelativeConfig)(pkgData, context.envName, context.caller));
|
||
|
|
||
|
if (ignoreFile && shouldIgnore(context, ignoreFile.ignore, null, ignoreFile.dirname)) {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
if (babelrcFile) {
|
||
|
const result = loadFileChain(validateBabelrcFile(babelrcFile), context);
|
||
|
if (!result) return null;
|
||
|
mergeChain(fileChain, result);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const chain = mergeChain(mergeChain(mergeChain(emptyChain(), configFileChain), fileChain), programmaticChain);
|
||
|
return {
|
||
|
plugins: dedupDescriptors(chain.plugins),
|
||
|
presets: dedupDescriptors(chain.presets),
|
||
|
options: chain.options.map(o => normalizeOptions(o)),
|
||
|
ignore: ignoreFile || undefined,
|
||
|
babelrc: babelrcFile || undefined,
|
||
|
config: configFile || undefined
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function babelrcLoadEnabled(context, pkgData, babelrcRoots, babelrcRootsDirectory) {
|
||
|
if (typeof babelrcRoots === "boolean") return babelrcRoots;
|
||
|
const absoluteRoot = context.root;
|
||
|
|
||
|
if (babelrcRoots === undefined) {
|
||
|
return pkgData.directories.indexOf(absoluteRoot) !== -1;
|
||
|
}
|
||
|
|
||
|
let babelrcPatterns = babelrcRoots;
|
||
|
if (!Array.isArray(babelrcPatterns)) babelrcPatterns = [babelrcPatterns];
|
||
|
babelrcPatterns = babelrcPatterns.map(pat => {
|
||
|
return typeof pat === "string" ? _path().default.resolve(babelrcRootsDirectory, pat) : pat;
|
||
|
});
|
||
|
|
||
|
if (babelrcPatterns.length === 1 && babelrcPatterns[0] === absoluteRoot) {
|
||
|
return pkgData.directories.indexOf(absoluteRoot) !== -1;
|
||
|
}
|
||
|
|
||
|
return babelrcPatterns.some(pat => {
|
||
|
if (typeof pat === "string") {
|
||
|
pat = (0, _patternToRegex.default)(pat, babelrcRootsDirectory);
|
||
|
}
|
||
|
|
||
|
return pkgData.directories.some(directory => {
|
||
|
return matchPattern(pat, babelrcRootsDirectory, directory, context);
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
|
||
|
const validateConfigFile = (0, _caching.makeWeakCache)(file => ({
|
||
|
filepath: file.filepath,
|
||
|
dirname: file.dirname,
|
||
|
options: (0, _options.validate)("configfile", file.options)
|
||
|
}));
|
||
|
const validateBabelrcFile = (0, _caching.makeWeakCache)(file => ({
|
||
|
filepath: file.filepath,
|
||
|
dirname: file.dirname,
|
||
|
options: (0, _options.validate)("babelrcfile", file.options)
|
||
|
}));
|
||
|
const validateExtendFile = (0, _caching.makeWeakCache)(file => ({
|
||
|
filepath: file.filepath,
|
||
|
dirname: file.dirname,
|
||
|
options: (0, _options.validate)("extendsfile", file.options)
|
||
|
}));
|
||
|
const loadProgrammaticChain = makeChainWalker({
|
||
|
root: input => buildRootDescriptors(input, "base", _configDescriptors.createCachedDescriptors),
|
||
|
env: (input, envName) => buildEnvDescriptors(input, "base", _configDescriptors.createCachedDescriptors, envName),
|
||
|
overrides: (input, index) => buildOverrideDescriptors(input, "base", _configDescriptors.createCachedDescriptors, index),
|
||
|
overridesEnv: (input, index, envName) => buildOverrideEnvDescriptors(input, "base", _configDescriptors.createCachedDescriptors, index, envName)
|
||
|
});
|
||
|
const loadFileChain = makeChainWalker({
|
||
|
root: file => loadFileDescriptors(file),
|
||
|
env: (file, envName) => loadFileEnvDescriptors(file)(envName),
|
||
|
overrides: (file, index) => loadFileOverridesDescriptors(file)(index),
|
||
|
overridesEnv: (file, index, envName) => loadFileOverridesEnvDescriptors(file)(index)(envName)
|
||
|
});
|
||
|
const loadFileDescriptors = (0, _caching.makeWeakCache)(file => buildRootDescriptors(file, file.filepath, _configDescriptors.createUncachedDescriptors));
|
||
|
const loadFileEnvDescriptors = (0, _caching.makeWeakCache)(file => (0, _caching.makeStrongCache)(envName => buildEnvDescriptors(file, file.filepath, _configDescriptors.createUncachedDescriptors, envName)));
|
||
|
const loadFileOverridesDescriptors = (0, _caching.makeWeakCache)(file => (0, _caching.makeStrongCache)(index => buildOverrideDescriptors(file, file.filepath, _configDescriptors.createUncachedDescriptors, index)));
|
||
|
const loadFileOverridesEnvDescriptors = (0, _caching.makeWeakCache)(file => (0, _caching.makeStrongCache)(index => (0, _caching.makeStrongCache)(envName => buildOverrideEnvDescriptors(file, file.filepath, _configDescriptors.createUncachedDescriptors, index, envName))));
|
||
|
|
||
|
function buildRootDescriptors({
|
||
|
dirname,
|
||
|
options
|
||
|
}, alias, descriptors) {
|
||
|
return descriptors(dirname, options, alias);
|
||
|
}
|
||
|
|
||
|
function buildEnvDescriptors({
|
||
|
dirname,
|
||
|
options
|
||
|
}, alias, descriptors, envName) {
|
||
|
const opts = options.env && options.env[envName];
|
||
|
return opts ? descriptors(dirname, opts, `${alias}.env["${envName}"]`) : null;
|
||
|
}
|
||
|
|
||
|
function buildOverrideDescriptors({
|
||
|
dirname,
|
||
|
options
|
||
|
}, alias, descriptors, index) {
|
||
|
const opts = options.overrides && options.overrides[index];
|
||
|
if (!opts) throw new Error("Assertion failure - missing override");
|
||
|
return descriptors(dirname, opts, `${alias}.overrides[${index}]`);
|
||
|
}
|
||
|
|
||
|
function buildOverrideEnvDescriptors({
|
||
|
dirname,
|
||
|
options
|
||
|
}, alias, descriptors, index, envName) {
|
||
|
const override = options.overrides && options.overrides[index];
|
||
|
if (!override) throw new Error("Assertion failure - missing override");
|
||
|
const opts = override.env && override.env[envName];
|
||
|
return opts ? descriptors(dirname, opts, `${alias}.overrides[${index}].env["${envName}"]`) : null;
|
||
|
}
|
||
|
|
||
|
function makeChainWalker({
|
||
|
root,
|
||
|
env,
|
||
|
overrides,
|
||
|
overridesEnv
|
||
|
}) {
|
||
|
return (input, context, files = new Set()) => {
|
||
|
const {
|
||
|
dirname
|
||
|
} = input;
|
||
|
const flattenedConfigs = [];
|
||
|
const rootOpts = root(input);
|
||
|
|
||
|
if (configIsApplicable(rootOpts, dirname, context)) {
|
||
|
flattenedConfigs.push(rootOpts);
|
||
|
const envOpts = env(input, context.envName);
|
||
|
|
||
|
if (envOpts && configIsApplicable(envOpts, dirname, context)) {
|
||
|
flattenedConfigs.push(envOpts);
|
||
|
}
|
||
|
|
||
|
(rootOpts.options.overrides || []).forEach((_, index) => {
|
||
|
const overrideOps = overrides(input, index);
|
||
|
|
||
|
if (configIsApplicable(overrideOps, dirname, context)) {
|
||
|
flattenedConfigs.push(overrideOps);
|
||
|
const overrideEnvOpts = overridesEnv(input, index, context.envName);
|
||
|
|
||
|
if (overrideEnvOpts && configIsApplicable(overrideEnvOpts, dirname, context)) {
|
||
|
flattenedConfigs.push(overrideEnvOpts);
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
if (flattenedConfigs.some(({
|
||
|
options: {
|
||
|
ignore,
|
||
|
only
|
||
|
}
|
||
|
}) => shouldIgnore(context, ignore, only, dirname))) {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
const chain = emptyChain();
|
||
|
|
||
|
for (const op of flattenedConfigs) {
|
||
|
if (!mergeExtendsChain(chain, op.options, dirname, context, files)) {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
mergeChainOpts(chain, op);
|
||
|
}
|
||
|
|
||
|
return chain;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function mergeExtendsChain(chain, opts, dirname, context, files) {
|
||
|
if (opts.extends === undefined) return true;
|
||
|
const file = (0, _files.loadConfig)(opts.extends, dirname, context.envName, context.caller);
|
||
|
|
||
|
if (files.has(file)) {
|
||
|
throw new Error(`Configuration cycle detected loading ${file.filepath}.\n` + `File already loaded following the config chain:\n` + Array.from(files, file => ` - ${file.filepath}`).join("\n"));
|
||
|
}
|
||
|
|
||
|
files.add(file);
|
||
|
const fileChain = loadFileChain(validateExtendFile(file), context, files);
|
||
|
files.delete(file);
|
||
|
if (!fileChain) return false;
|
||
|
mergeChain(chain, fileChain);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
function mergeChain(target, source) {
|
||
|
target.options.push(...source.options);
|
||
|
target.plugins.push(...source.plugins);
|
||
|
target.presets.push(...source.presets);
|
||
|
return target;
|
||
|
}
|
||
|
|
||
|
function mergeChainOpts(target, {
|
||
|
options,
|
||
|
plugins,
|
||
|
presets
|
||
|
}) {
|
||
|
target.options.push(options);
|
||
|
target.plugins.push(...plugins());
|
||
|
target.presets.push(...presets());
|
||
|
return target;
|
||
|
}
|
||
|
|
||
|
function emptyChain() {
|
||
|
return {
|
||
|
options: [],
|
||
|
presets: [],
|
||
|
plugins: []
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function normalizeOptions(opts) {
|
||
|
const options = Object.assign({}, opts);
|
||
|
delete options.extends;
|
||
|
delete options.env;
|
||
|
delete options.overrides;
|
||
|
delete options.plugins;
|
||
|
delete options.presets;
|
||
|
delete options.passPerPreset;
|
||
|
delete options.ignore;
|
||
|
delete options.only;
|
||
|
delete options.test;
|
||
|
delete options.include;
|
||
|
delete options.exclude;
|
||
|
|
||
|
if (options.hasOwnProperty("sourceMap")) {
|
||
|
options.sourceMaps = options.sourceMap;
|
||
|
delete options.sourceMap;
|
||
|
}
|
||
|
|
||
|
return options;
|
||
|
}
|
||
|
|
||
|
function dedupDescriptors(items) {
|
||
|
const map = new Map();
|
||
|
const descriptors = [];
|
||
|
|
||
|
for (const item of items) {
|
||
|
if (typeof item.value === "function") {
|
||
|
const fnKey = item.value;
|
||
|
let nameMap = map.get(fnKey);
|
||
|
|
||
|
if (!nameMap) {
|
||
|
nameMap = new Map();
|
||
|
map.set(fnKey, nameMap);
|
||
|
}
|
||
|
|
||
|
let desc = nameMap.get(item.name);
|
||
|
|
||
|
if (!desc) {
|
||
|
desc = {
|
||
|
value: item
|
||
|
};
|
||
|
descriptors.push(desc);
|
||
|
if (!item.ownPass) nameMap.set(item.name, desc);
|
||
|
} else {
|
||
|
desc.value = item;
|
||
|
}
|
||
|
} else {
|
||
|
descriptors.push({
|
||
|
value: item
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return descriptors.reduce((acc, desc) => {
|
||
|
acc.push(desc.value);
|
||
|
return acc;
|
||
|
}, []);
|
||
|
}
|
||
|
|
||
|
function configIsApplicable({
|
||
|
options
|
||
|
}, dirname, context) {
|
||
|
return (options.test === undefined || configFieldIsApplicable(context, options.test, dirname)) && (options.include === undefined || configFieldIsApplicable(context, options.include, dirname)) && (options.exclude === undefined || !configFieldIsApplicable(context, options.exclude, dirname));
|
||
|
}
|
||
|
|
||
|
function configFieldIsApplicable(context, test, dirname) {
|
||
|
const patterns = Array.isArray(test) ? test : [test];
|
||
|
return matchesPatterns(context, patterns, dirname);
|
||
|
}
|
||
|
|
||
|
function shouldIgnore(context, ignore, only, dirname) {
|
||
|
if (ignore && matchesPatterns(context, ignore, dirname)) {
|
||
|
debug("Ignored %o because it matched one of %O from %o", context.filename, ignore, dirname);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if (only && !matchesPatterns(context, only, dirname)) {
|
||
|
debug("Ignored %o because it failed to match one of %O from %o", context.filename, only, dirname);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
function matchesPatterns(context, patterns, dirname) {
|
||
|
return patterns.some(pattern => matchPattern(pattern, dirname, context.filename, context));
|
||
|
}
|
||
|
|
||
|
function matchPattern(pattern, dirname, pathToTest, context) {
|
||
|
if (typeof pattern === "function") {
|
||
|
return !!pattern(pathToTest, {
|
||
|
dirname,
|
||
|
envName: context.envName,
|
||
|
caller: context.caller
|
||
|
});
|
||
|
}
|
||
|
|
||
|
if (typeof pathToTest !== "string") {
|
||
|
throw new Error(`Configuration contains string/RegExp pattern, but no filename was passed to Babel`);
|
||
|
}
|
||
|
|
||
|
if (typeof pattern === "string") {
|
||
|
pattern = (0, _patternToRegex.default)(pattern, dirname);
|
||
|
}
|
||
|
|
||
|
return pattern.test(pathToTest);
|
||
|
}
|