apply-extends.js 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. import { YError } from '../yerror.js';
  2. let previouslyVisitedConfigs = [];
  3. let shim;
  4. export function applyExtends(config, cwd, mergeExtends, _shim) {
  5. shim = _shim;
  6. let defaultConfig = {};
  7. if (Object.prototype.hasOwnProperty.call(config, 'extends')) {
  8. if (typeof config.extends !== 'string')
  9. return defaultConfig;
  10. const isPath = /\.json|\..*rc$/.test(config.extends);
  11. let pathToDefault = null;
  12. if (!isPath) {
  13. try {
  14. pathToDefault = require.resolve(config.extends);
  15. }
  16. catch (_err) {
  17. return config;
  18. }
  19. }
  20. else {
  21. pathToDefault = getPathToDefaultConfig(cwd, config.extends);
  22. }
  23. checkForCircularExtends(pathToDefault);
  24. previouslyVisitedConfigs.push(pathToDefault);
  25. defaultConfig = isPath
  26. ? JSON.parse(shim.readFileSync(pathToDefault, 'utf8'))
  27. : require(config.extends);
  28. delete config.extends;
  29. defaultConfig = applyExtends(defaultConfig, shim.path.dirname(pathToDefault), mergeExtends, shim);
  30. }
  31. previouslyVisitedConfigs = [];
  32. return mergeExtends
  33. ? mergeDeep(defaultConfig, config)
  34. : Object.assign({}, defaultConfig, config);
  35. }
  36. function checkForCircularExtends(cfgPath) {
  37. if (previouslyVisitedConfigs.indexOf(cfgPath) > -1) {
  38. throw new YError(`Circular extended configurations: '${cfgPath}'.`);
  39. }
  40. }
  41. function getPathToDefaultConfig(cwd, pathToExtend) {
  42. return shim.path.resolve(cwd, pathToExtend);
  43. }
  44. function mergeDeep(config1, config2) {
  45. const target = {};
  46. function isObject(obj) {
  47. return obj && typeof obj === 'object' && !Array.isArray(obj);
  48. }
  49. Object.assign(target, config1);
  50. for (const key of Object.keys(config2)) {
  51. if (isObject(config2[key]) && isObject(target[key])) {
  52. target[key] = mergeDeep(config1[key], config2[key]);
  53. }
  54. else {
  55. target[key] = config2[key];
  56. }
  57. }
  58. return target;
  59. }