config-chain.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.buildPresetChain = buildPresetChain;
  6. exports.buildRootChain = buildRootChain;
  7. exports.buildPresetChainWalker = void 0;
  8. function _path() {
  9. const data = _interopRequireDefault(require("path"));
  10. _path = function () {
  11. return data;
  12. };
  13. return data;
  14. }
  15. function _debug() {
  16. const data = _interopRequireDefault(require("debug"));
  17. _debug = function () {
  18. return data;
  19. };
  20. return data;
  21. }
  22. var _options = require("./validation/options");
  23. var _patternToRegex = _interopRequireDefault(require("./pattern-to-regex"));
  24. var _printer = require("./printer");
  25. var _files = require("./files");
  26. var _caching = require("./caching");
  27. var _configDescriptors = require("./config-descriptors");
  28. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  29. const debug = (0, _debug().default)("babel:config:config-chain");
  30. function* buildPresetChain(arg, context) {
  31. const chain = yield* buildPresetChainWalker(arg, context);
  32. if (!chain) return null;
  33. return {
  34. plugins: dedupDescriptors(chain.plugins),
  35. presets: dedupDescriptors(chain.presets),
  36. options: chain.options.map(o => normalizeOptions(o)),
  37. files: new Set()
  38. };
  39. }
  40. const buildPresetChainWalker = makeChainWalker({
  41. root: preset => loadPresetDescriptors(preset),
  42. env: (preset, envName) => loadPresetEnvDescriptors(preset)(envName),
  43. overrides: (preset, index) => loadPresetOverridesDescriptors(preset)(index),
  44. overridesEnv: (preset, index, envName) => loadPresetOverridesEnvDescriptors(preset)(index)(envName),
  45. createLogger: () => () => {}
  46. });
  47. exports.buildPresetChainWalker = buildPresetChainWalker;
  48. const loadPresetDescriptors = (0, _caching.makeWeakCacheSync)(preset => buildRootDescriptors(preset, preset.alias, _configDescriptors.createUncachedDescriptors));
  49. const loadPresetEnvDescriptors = (0, _caching.makeWeakCacheSync)(preset => (0, _caching.makeStrongCacheSync)(envName => buildEnvDescriptors(preset, preset.alias, _configDescriptors.createUncachedDescriptors, envName)));
  50. const loadPresetOverridesDescriptors = (0, _caching.makeWeakCacheSync)(preset => (0, _caching.makeStrongCacheSync)(index => buildOverrideDescriptors(preset, preset.alias, _configDescriptors.createUncachedDescriptors, index)));
  51. const loadPresetOverridesEnvDescriptors = (0, _caching.makeWeakCacheSync)(preset => (0, _caching.makeStrongCacheSync)(index => (0, _caching.makeStrongCacheSync)(envName => buildOverrideEnvDescriptors(preset, preset.alias, _configDescriptors.createUncachedDescriptors, index, envName))));
  52. function* buildRootChain(opts, context) {
  53. let configReport, babelRcReport;
  54. const programmaticLogger = new _printer.ConfigPrinter();
  55. const programmaticChain = yield* loadProgrammaticChain({
  56. options: opts,
  57. dirname: context.cwd
  58. }, context, undefined, programmaticLogger);
  59. if (!programmaticChain) return null;
  60. const programmaticReport = programmaticLogger.output();
  61. let configFile;
  62. if (typeof opts.configFile === "string") {
  63. configFile = yield* (0, _files.loadConfig)(opts.configFile, context.cwd, context.envName, context.caller);
  64. } else if (opts.configFile !== false) {
  65. configFile = yield* (0, _files.findRootConfig)(context.root, context.envName, context.caller);
  66. }
  67. let {
  68. babelrc,
  69. babelrcRoots
  70. } = opts;
  71. let babelrcRootsDirectory = context.cwd;
  72. const configFileChain = emptyChain();
  73. const configFileLogger = new _printer.ConfigPrinter();
  74. if (configFile) {
  75. const validatedFile = validateConfigFile(configFile);
  76. const result = yield* loadFileChain(validatedFile, context, undefined, configFileLogger);
  77. if (!result) return null;
  78. configReport = configFileLogger.output();
  79. if (babelrc === undefined) {
  80. babelrc = validatedFile.options.babelrc;
  81. }
  82. if (babelrcRoots === undefined) {
  83. babelrcRootsDirectory = validatedFile.dirname;
  84. babelrcRoots = validatedFile.options.babelrcRoots;
  85. }
  86. mergeChain(configFileChain, result);
  87. }
  88. const pkgData = typeof context.filename === "string" ? yield* (0, _files.findPackageData)(context.filename) : null;
  89. let ignoreFile, babelrcFile;
  90. let isIgnored = false;
  91. const fileChain = emptyChain();
  92. if ((babelrc === true || babelrc === undefined) && pkgData && babelrcLoadEnabled(context, pkgData, babelrcRoots, babelrcRootsDirectory)) {
  93. ({
  94. ignore: ignoreFile,
  95. config: babelrcFile
  96. } = yield* (0, _files.findRelativeConfig)(pkgData, context.envName, context.caller));
  97. if (ignoreFile) {
  98. fileChain.files.add(ignoreFile.filepath);
  99. }
  100. if (ignoreFile && shouldIgnore(context, ignoreFile.ignore, null, ignoreFile.dirname)) {
  101. isIgnored = true;
  102. }
  103. if (babelrcFile && !isIgnored) {
  104. const validatedFile = validateBabelrcFile(babelrcFile);
  105. const babelrcLogger = new _printer.ConfigPrinter();
  106. const result = yield* loadFileChain(validatedFile, context, undefined, babelrcLogger);
  107. if (!result) {
  108. isIgnored = true;
  109. } else {
  110. babelRcReport = babelrcLogger.output();
  111. mergeChain(fileChain, result);
  112. }
  113. }
  114. if (babelrcFile && isIgnored) {
  115. fileChain.files.add(babelrcFile.filepath);
  116. }
  117. }
  118. if (context.showConfig) {
  119. console.log(`Babel configs on "${context.filename}" (ascending priority):\n` + [configReport, babelRcReport, programmaticReport].filter(x => !!x).join("\n\n"));
  120. return null;
  121. }
  122. const chain = mergeChain(mergeChain(mergeChain(emptyChain(), configFileChain), fileChain), programmaticChain);
  123. return {
  124. plugins: isIgnored ? [] : dedupDescriptors(chain.plugins),
  125. presets: isIgnored ? [] : dedupDescriptors(chain.presets),
  126. options: isIgnored ? [] : chain.options.map(o => normalizeOptions(o)),
  127. fileHandling: isIgnored ? "ignored" : "transpile",
  128. ignore: ignoreFile || undefined,
  129. babelrc: babelrcFile || undefined,
  130. config: configFile || undefined,
  131. files: chain.files
  132. };
  133. }
  134. function babelrcLoadEnabled(context, pkgData, babelrcRoots, babelrcRootsDirectory) {
  135. if (typeof babelrcRoots === "boolean") return babelrcRoots;
  136. const absoluteRoot = context.root;
  137. if (babelrcRoots === undefined) {
  138. return pkgData.directories.indexOf(absoluteRoot) !== -1;
  139. }
  140. let babelrcPatterns = babelrcRoots;
  141. if (!Array.isArray(babelrcPatterns)) babelrcPatterns = [babelrcPatterns];
  142. babelrcPatterns = babelrcPatterns.map(pat => {
  143. return typeof pat === "string" ? _path().default.resolve(babelrcRootsDirectory, pat) : pat;
  144. });
  145. if (babelrcPatterns.length === 1 && babelrcPatterns[0] === absoluteRoot) {
  146. return pkgData.directories.indexOf(absoluteRoot) !== -1;
  147. }
  148. return babelrcPatterns.some(pat => {
  149. if (typeof pat === "string") {
  150. pat = (0, _patternToRegex.default)(pat, babelrcRootsDirectory);
  151. }
  152. return pkgData.directories.some(directory => {
  153. return matchPattern(pat, babelrcRootsDirectory, directory, context);
  154. });
  155. });
  156. }
  157. const validateConfigFile = (0, _caching.makeWeakCacheSync)(file => ({
  158. filepath: file.filepath,
  159. dirname: file.dirname,
  160. options: (0, _options.validate)("configfile", file.options)
  161. }));
  162. const validateBabelrcFile = (0, _caching.makeWeakCacheSync)(file => ({
  163. filepath: file.filepath,
  164. dirname: file.dirname,
  165. options: (0, _options.validate)("babelrcfile", file.options)
  166. }));
  167. const validateExtendFile = (0, _caching.makeWeakCacheSync)(file => ({
  168. filepath: file.filepath,
  169. dirname: file.dirname,
  170. options: (0, _options.validate)("extendsfile", file.options)
  171. }));
  172. const loadProgrammaticChain = makeChainWalker({
  173. root: input => buildRootDescriptors(input, "base", _configDescriptors.createCachedDescriptors),
  174. env: (input, envName) => buildEnvDescriptors(input, "base", _configDescriptors.createCachedDescriptors, envName),
  175. overrides: (input, index) => buildOverrideDescriptors(input, "base", _configDescriptors.createCachedDescriptors, index),
  176. overridesEnv: (input, index, envName) => buildOverrideEnvDescriptors(input, "base", _configDescriptors.createCachedDescriptors, index, envName),
  177. createLogger: (input, context, baseLogger) => buildProgrammaticLogger(input, context, baseLogger)
  178. });
  179. const loadFileChainWalker = makeChainWalker({
  180. root: file => loadFileDescriptors(file),
  181. env: (file, envName) => loadFileEnvDescriptors(file)(envName),
  182. overrides: (file, index) => loadFileOverridesDescriptors(file)(index),
  183. overridesEnv: (file, index, envName) => loadFileOverridesEnvDescriptors(file)(index)(envName),
  184. createLogger: (file, context, baseLogger) => buildFileLogger(file.filepath, context, baseLogger)
  185. });
  186. function* loadFileChain(input, context, files, baseLogger) {
  187. const chain = yield* loadFileChainWalker(input, context, files, baseLogger);
  188. if (chain) {
  189. chain.files.add(input.filepath);
  190. }
  191. return chain;
  192. }
  193. const loadFileDescriptors = (0, _caching.makeWeakCacheSync)(file => buildRootDescriptors(file, file.filepath, _configDescriptors.createUncachedDescriptors));
  194. const loadFileEnvDescriptors = (0, _caching.makeWeakCacheSync)(file => (0, _caching.makeStrongCacheSync)(envName => buildEnvDescriptors(file, file.filepath, _configDescriptors.createUncachedDescriptors, envName)));
  195. const loadFileOverridesDescriptors = (0, _caching.makeWeakCacheSync)(file => (0, _caching.makeStrongCacheSync)(index => buildOverrideDescriptors(file, file.filepath, _configDescriptors.createUncachedDescriptors, index)));
  196. const loadFileOverridesEnvDescriptors = (0, _caching.makeWeakCacheSync)(file => (0, _caching.makeStrongCacheSync)(index => (0, _caching.makeStrongCacheSync)(envName => buildOverrideEnvDescriptors(file, file.filepath, _configDescriptors.createUncachedDescriptors, index, envName))));
  197. function buildFileLogger(filepath, context, baseLogger) {
  198. if (!baseLogger) {
  199. return () => {};
  200. }
  201. return baseLogger.configure(context.showConfig, _printer.ChainFormatter.Config, {
  202. filepath
  203. });
  204. }
  205. function buildRootDescriptors({
  206. dirname,
  207. options
  208. }, alias, descriptors) {
  209. return descriptors(dirname, options, alias);
  210. }
  211. function buildProgrammaticLogger(_, context, baseLogger) {
  212. var _context$caller;
  213. if (!baseLogger) {
  214. return () => {};
  215. }
  216. return baseLogger.configure(context.showConfig, _printer.ChainFormatter.Programmatic, {
  217. callerName: (_context$caller = context.caller) == null ? void 0 : _context$caller.name
  218. });
  219. }
  220. function buildEnvDescriptors({
  221. dirname,
  222. options
  223. }, alias, descriptors, envName) {
  224. const opts = options.env && options.env[envName];
  225. return opts ? descriptors(dirname, opts, `${alias}.env["${envName}"]`) : null;
  226. }
  227. function buildOverrideDescriptors({
  228. dirname,
  229. options
  230. }, alias, descriptors, index) {
  231. const opts = options.overrides && options.overrides[index];
  232. if (!opts) throw new Error("Assertion failure - missing override");
  233. return descriptors(dirname, opts, `${alias}.overrides[${index}]`);
  234. }
  235. function buildOverrideEnvDescriptors({
  236. dirname,
  237. options
  238. }, alias, descriptors, index, envName) {
  239. const override = options.overrides && options.overrides[index];
  240. if (!override) throw new Error("Assertion failure - missing override");
  241. const opts = override.env && override.env[envName];
  242. return opts ? descriptors(dirname, opts, `${alias}.overrides[${index}].env["${envName}"]`) : null;
  243. }
  244. function makeChainWalker({
  245. root,
  246. env,
  247. overrides,
  248. overridesEnv,
  249. createLogger
  250. }) {
  251. return function* (input, context, files = new Set(), baseLogger) {
  252. const {
  253. dirname
  254. } = input;
  255. const flattenedConfigs = [];
  256. const rootOpts = root(input);
  257. if (configIsApplicable(rootOpts, dirname, context)) {
  258. flattenedConfigs.push({
  259. config: rootOpts,
  260. envName: undefined,
  261. index: undefined
  262. });
  263. const envOpts = env(input, context.envName);
  264. if (envOpts && configIsApplicable(envOpts, dirname, context)) {
  265. flattenedConfigs.push({
  266. config: envOpts,
  267. envName: context.envName,
  268. index: undefined
  269. });
  270. }
  271. (rootOpts.options.overrides || []).forEach((_, index) => {
  272. const overrideOps = overrides(input, index);
  273. if (configIsApplicable(overrideOps, dirname, context)) {
  274. flattenedConfigs.push({
  275. config: overrideOps,
  276. index,
  277. envName: undefined
  278. });
  279. const overrideEnvOpts = overridesEnv(input, index, context.envName);
  280. if (overrideEnvOpts && configIsApplicable(overrideEnvOpts, dirname, context)) {
  281. flattenedConfigs.push({
  282. config: overrideEnvOpts,
  283. index,
  284. envName: context.envName
  285. });
  286. }
  287. }
  288. });
  289. }
  290. if (flattenedConfigs.some(({
  291. config: {
  292. options: {
  293. ignore,
  294. only
  295. }
  296. }
  297. }) => shouldIgnore(context, ignore, only, dirname))) {
  298. return null;
  299. }
  300. const chain = emptyChain();
  301. const logger = createLogger(input, context, baseLogger);
  302. for (const {
  303. config,
  304. index,
  305. envName
  306. } of flattenedConfigs) {
  307. if (!(yield* mergeExtendsChain(chain, config.options, dirname, context, files, baseLogger))) {
  308. return null;
  309. }
  310. logger(config, index, envName);
  311. mergeChainOpts(chain, config);
  312. }
  313. return chain;
  314. };
  315. }
  316. function* mergeExtendsChain(chain, opts, dirname, context, files, baseLogger) {
  317. if (opts.extends === undefined) return true;
  318. const file = yield* (0, _files.loadConfig)(opts.extends, dirname, context.envName, context.caller);
  319. if (files.has(file)) {
  320. 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"));
  321. }
  322. files.add(file);
  323. const fileChain = yield* loadFileChain(validateExtendFile(file), context, files, baseLogger);
  324. files.delete(file);
  325. if (!fileChain) return false;
  326. mergeChain(chain, fileChain);
  327. return true;
  328. }
  329. function mergeChain(target, source) {
  330. target.options.push(...source.options);
  331. target.plugins.push(...source.plugins);
  332. target.presets.push(...source.presets);
  333. for (const file of source.files) {
  334. target.files.add(file);
  335. }
  336. return target;
  337. }
  338. function mergeChainOpts(target, {
  339. options,
  340. plugins,
  341. presets
  342. }) {
  343. target.options.push(options);
  344. target.plugins.push(...plugins());
  345. target.presets.push(...presets());
  346. return target;
  347. }
  348. function emptyChain() {
  349. return {
  350. options: [],
  351. presets: [],
  352. plugins: [],
  353. files: new Set()
  354. };
  355. }
  356. function normalizeOptions(opts) {
  357. const options = Object.assign({}, opts);
  358. delete options.extends;
  359. delete options.env;
  360. delete options.overrides;
  361. delete options.plugins;
  362. delete options.presets;
  363. delete options.passPerPreset;
  364. delete options.ignore;
  365. delete options.only;
  366. delete options.test;
  367. delete options.include;
  368. delete options.exclude;
  369. if (Object.prototype.hasOwnProperty.call(options, "sourceMap")) {
  370. options.sourceMaps = options.sourceMap;
  371. delete options.sourceMap;
  372. }
  373. return options;
  374. }
  375. function dedupDescriptors(items) {
  376. const map = new Map();
  377. const descriptors = [];
  378. for (const item of items) {
  379. if (typeof item.value === "function") {
  380. const fnKey = item.value;
  381. let nameMap = map.get(fnKey);
  382. if (!nameMap) {
  383. nameMap = new Map();
  384. map.set(fnKey, nameMap);
  385. }
  386. let desc = nameMap.get(item.name);
  387. if (!desc) {
  388. desc = {
  389. value: item
  390. };
  391. descriptors.push(desc);
  392. if (!item.ownPass) nameMap.set(item.name, desc);
  393. } else {
  394. desc.value = item;
  395. }
  396. } else {
  397. descriptors.push({
  398. value: item
  399. });
  400. }
  401. }
  402. return descriptors.reduce((acc, desc) => {
  403. acc.push(desc.value);
  404. return acc;
  405. }, []);
  406. }
  407. function configIsApplicable({
  408. options
  409. }, dirname, context) {
  410. 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));
  411. }
  412. function configFieldIsApplicable(context, test, dirname) {
  413. const patterns = Array.isArray(test) ? test : [test];
  414. return matchesPatterns(context, patterns, dirname);
  415. }
  416. function shouldIgnore(context, ignore, only, dirname) {
  417. if (ignore && matchesPatterns(context, ignore, dirname)) {
  418. var _context$filename;
  419. const message = `No config is applied to "${(_context$filename = context.filename) != null ? _context$filename : "(unknown)"}" because it matches one of \`ignore: ${JSON.stringify(ignore)}\` from "${dirname}"`;
  420. debug(message);
  421. if (context.showConfig) {
  422. console.log(message);
  423. }
  424. return true;
  425. }
  426. if (only && !matchesPatterns(context, only, dirname)) {
  427. var _context$filename2;
  428. const message = `No config is applied to "${(_context$filename2 = context.filename) != null ? _context$filename2 : "(unknown)"}" because it fails to match one of \`only: ${JSON.stringify(only)}\` from "${dirname}"`;
  429. debug(message);
  430. if (context.showConfig) {
  431. console.log(message);
  432. }
  433. return true;
  434. }
  435. return false;
  436. }
  437. function matchesPatterns(context, patterns, dirname) {
  438. return patterns.some(pattern => matchPattern(pattern, dirname, context.filename, context));
  439. }
  440. function matchPattern(pattern, dirname, pathToTest, context) {
  441. if (typeof pattern === "function") {
  442. return !!pattern(pathToTest, {
  443. dirname,
  444. envName: context.envName,
  445. caller: context.caller
  446. });
  447. }
  448. if (typeof pathToTest !== "string") {
  449. throw new Error(`Configuration contains string/RegExp pattern, but no filename was passed to Babel`);
  450. }
  451. if (typeof pattern === "string") {
  452. pattern = (0, _patternToRegex.default)(pattern, dirname);
  453. }
  454. return pattern.test(pathToTest);
  455. }