lib/lmd_common.js
function (rawConfig, configFile, configDir, flagsNames, extraOptions, usedConfigs) {
    flagsNames = flagsNames || Object.keys(LMD_PLUGINS);

    var isFirstRun = typeof usedConfigs === "undefined";

    usedConfigs = usedConfigs || {};
    usedConfigs[configFile] = true; // mark config as used

    var configs = [],
        resultConfig = {
            modules: {},
            errors: [],
            plugins_depends: {}
        };

    if (extraOptions && extraOptions.mixins) {
        rawConfig = mergeMixins(rawConfig, extraOptions.mixins);
    }

    if (extraOptions && extraOptions.styles) {
        rawConfig = deepDestructableMerge(rawConfig, {
            styles: extraOptions.styles
        });
    }

    // collect modules and module options
    var modules = collectModules(rawConfig, configDir);
    if (rawConfig.depends) {
        var /*dependsMask = rawConfig.depends === true ? DEFAULT_DEPENDS_MASK : rawConfig.depends,*/
            dependsConfigPath,
            dependsMask;
        for (var moduleName in modules) {
            if (!modules[moduleName].is_shortcut && !modules[moduleName].is_ignored) {
                dependsMask = modules[moduleName].depends;
                dependsConfigPath = getDependsConfigOf(modules[moduleName].path, dependsMask);
                dependsConfigPath.forEach(function (dependsConfigPath) {
                    if (fileExists(dependsConfigPath)) {
                        if (!usedConfigs[dependsConfigPath]) {
                            configs.unshift({
                                context: 'depends config **' + dependsConfigPath + '**',
                                config: assembleLmdConfig(dependsConfigPath, flagsNames, null, usedConfigs)
                            });
                        }
                    }
                });
            }
        }
    }

    // extend parent config
    if (typeof rawConfig['extends'] === "string") {
        var parentConfigFile = fs.realpathSync(configDir + '/' + rawConfig['extends']);
        if (!usedConfigs[parentConfigFile]) {
            var parentConfig = assembleLmdConfig(parentConfigFile, flagsNames, null, usedConfigs);
        }
    }

    var processedConfig = {
        modules: modules,
        styles: collectStyles(rawConfig, configDir),
        bundles: collectBundles(rawConfig, configDir),
        plugins: collectUserPlugins(rawConfig, configDir)
    };

    // keep fields
    MASTER_FIELDS.forEach(function (fieldName) {
        processedConfig[fieldName] = rawConfig[fieldName];
        if (FILED_ALIASES.hasOwnProperty(fieldName)) {
            processedConfig[FILED_ALIASES[fieldName]] = rawConfig[fieldName];
        }
    });

    // keep flags
    flagsNames.forEach(function (fieldName) {
        processedConfig[fieldName] = rawConfig[fieldName];
    });

    if (parentConfig) {
        mergeConfigs(resultConfig, parentConfig, flagsNames, INHERITABLE_FIELDS, true, 'parent config **' + parentConfigFile + '**');
    }

    for (var i = 0, c = configs.length, dependsMainModuleName; i < c; i++) {
        // Cleanup main module from depends
        dependsMainModuleName = configs[i].config.main || "main";
        if (configs[i].config.modules) {
            delete configs[i].config.modules[dependsMainModuleName];
        }
        mergeConfigs(resultConfig, configs[i].config, flagsNames, [], false, configs[i].context);
    }

    mergeConfigs(resultConfig, processedConfig, flagsNames, MASTER_FIELDS, true, 'main config **' + configFile + '**');

    if (isFirstRun) {
        // Apply mixins
        var mixins = resultConfig.mixins;
        if (Array.isArray(mixins)) {
            mixins.forEach(function (mixinName) {
                var mixinConfigFile = fs.realpathSync(configDir + '/' + mixinName),
                    processedMixin = assembleLmdConfig(mixinConfigFile, flagsNames, null, usedConfigs);

                mergeConfigs(resultConfig, processedMixin, flagsNames, INHERITABLE_FIELDS, true, 'mixin config **' + mixinConfigFile + '**');
            });
        }
        if (extraOptions) {
            extraOptions.modules = collectModules(extraOptions, configDir);
            extraOptions.bundles = collectBundles(extraOptions, configDir);
            extraOptions.styles = collectStyles(extraOptions, configDir);
            mergeConfigs(resultConfig, extraOptions, flagsNames, EXTRA_OPTIONS_FIELDS, true, 'CLI options');
        }
        reapplyModuleOptions(resultConfig);
        addPluginsFromBundles(resultConfig);
        addPluginsDepends(resultConfig);
        flattenBundles(resultConfig);
        resolveStyles(resultConfig);
        bundlesInheritFieldsFromPackage(resultConfig);
        removeIgnoredModules(resultConfig);
    }
    return resultConfig;
}
function (rawConfig, configFile, configDir, flagsNames, extraOptions, usedConfigs) {
    flagsNames = flagsNames || Object.keys(LMD_PLUGINS);

    var isFirstRun = typeof usedConfigs === "undefined";

    usedConfigs = usedConfigs || {};
    usedConfigs[configFile] = true; // mark config as used

    var configs = [],
        resultConfig = {
            modules: {},
            errors: [],
            plugins_depends: {}
        };

    if (extraOptions && extraOptions.mixins) {
        rawConfig = mergeMixins(rawConfig, extraOptions.mixins);
    }

    if (extraOptions && extraOptions.styles) {
        rawConfig = deepDestructableMerge(rawConfig, {
            styles: extraOptions.styles
        });
    }

    // collect modules and module options
    var modules = collectModules(rawConfig, configDir);
    if (rawConfig.depends) {
        var /*dependsMask = rawConfig.depends === true ? DEFAULT_DEPENDS_MASK : rawConfig.depends,*/
            dependsConfigPath,
            dependsMask;
        for (var moduleName in modules) {
            if (!modules[moduleName].is_shortcut && !modules[moduleName].is_ignored) {
                dependsMask = modules[moduleName].depends;
                dependsConfigPath = getDependsConfigOf(modules[moduleName].path, dependsMask);
                dependsConfigPath.forEach(function (dependsConfigPath) {
                    if (fileExists(dependsConfigPath)) {
                        if (!usedConfigs[dependsConfigPath]) {
                            configs.unshift({
                                context: 'depends config **' + dependsConfigPath + '**',
                                config: assembleLmdConfig(dependsConfigPath, flagsNames, null, usedConfigs)
                            });
                        }
                    }
                });
            }
        }
    }

    // extend parent config
    if (typeof rawConfig['extends'] === "string") {
        var parentConfigFile = fs.realpathSync(configDir + '/' + rawConfig['extends']);
        if (!usedConfigs[parentConfigFile]) {
            var parentConfig = assembleLmdConfig(parentConfigFile, flagsNames, null, usedConfigs);
        }
    }

    var processedConfig = {
        modules: modules,
        styles: collectStyles(rawConfig, configDir),
        bundles: collectBundles(rawConfig, configDir),
        plugins: collectUserPlugins(rawConfig, configDir)
    };

    // keep fields
    MASTER_FIELDS.forEach(function (fieldName) {
        processedConfig[fieldName] = rawConfig[fieldName];
        if (FILED_ALIASES.hasOwnProperty(fieldName)) {
            processedConfig[FILED_ALIASES[fieldName]] = rawConfig[fieldName];
        }
    });

    // keep flags
    flagsNames.forEach(function (fieldName) {
        processedConfig[fieldName] = rawConfig[fieldName];
    });

    if (parentConfig) {
        mergeConfigs(resultConfig, parentConfig, flagsNames, INHERITABLE_FIELDS, true, 'parent config **' + parentConfigFile + '**');
    }

    for (var i = 0, c = configs.length, dependsMainModuleName; i < c; i++) {
        // Cleanup main module from depends
        dependsMainModuleName = configs[i].config.main || "main";
        if (configs[i].config.modules) {
            delete configs[i].config.modules[dependsMainModuleName];
        }
        mergeConfigs(resultConfig, configs[i].config, flagsNames, [], false, configs[i].context);
    }

    mergeConfigs(resultConfig, processedConfig, flagsNames, MASTER_FIELDS, true, 'main config **' + configFile + '**');

    if (isFirstRun) {
        // Apply mixins
        var mixins = resultConfig.mixins;
        if (Array.isArray(mixins)) {
            mixins.forEach(function (mixinName) {
                var mixinConfigFile = fs.realpathSync(configDir + '/' + mixinName),
                    processedMixin = assembleLmdConfig(mixinConfigFile, flagsNames, null, usedConfigs);

                mergeConfigs(resultConfig, processedMixin, flagsNames, INHERITABLE_FIELDS, true, 'mixin config **' + mixinConfigFile + '**');
            });
        }
        if (extraOptions) {
            extraOptions.modules = collectModules(extraOptions, configDir);
            extraOptions.bundles = collectBundles(extraOptions, configDir);
            extraOptions.styles = collectStyles(extraOptions, configDir);
            mergeConfigs(resultConfig, extraOptions, flagsNames, EXTRA_OPTIONS_FIELDS, true, 'CLI options');
        }
        reapplyModuleOptions(resultConfig);
        addPluginsFromBundles(resultConfig);
        addPluginsDepends(resultConfig);
        flattenBundles(resultConfig);
        resolveStyles(resultConfig);
        bundlesInheritFieldsFromPackage(resultConfig);
        removeIgnoredModules(resultConfig);
    }
    return resultConfig;
}
Creates LMD config: applies depends and extends

@param {Object}   rawConfig
@param {String}   configFile
@param {String}   configDir
@param {String[]} [flagsNames]
@param {Object}   [extraOptions]
@param {Object}   [usedConfigs]

@return {Object}