UNPKG

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