config-chain.js 18 KB

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