1import { YError } from '../yerror.js';
2let previouslyVisitedConfigs = [];
3let shim;
4export 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}
36function checkForCircularExtends(cfgPath) {
37    if (previouslyVisitedConfigs.indexOf(cfgPath) > -1) {
38        throw new YError(`Circular extended configurations: '${cfgPath}'.`);
39    }
40}
41function getPathToDefaultConfig(cwd, pathToExtend) {
42    return shim.path.resolve(cwd, pathToExtend);
43}
44function 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}
60