<commit_before>var Utils = require("./utilities");
var DeepClone = require("lodash.clonedeep");
var Merge = require("lodash.mergewith");

function validate(input) {
    // Check it's an object.
    if (!Utils.isObject(input))
        throw new Error("You must provide a loader config object.");

    // Ensure 'test', 'exclude', and 'include' properties are regex values.
    ["test", "exclude", "include"].forEach(function(property) {
        var value = input[property];

        if (Utils.isDefined(value) && !Utils.isRegex(value))
            throw new Error("You must provide a regex value for '" + property + "'.");
    });

    // Ensure the 'loader' property is a string.
    if (Utils.isDefined(input.loader) && !Utils.isString(input.loader))
        throw new Error("You must provide a string value for 'loader'.");

    // Ensure the 'loaders' property is an array of strings.
    if (Utils.isDefined(input.loaders)) {
        if (!Utils.isArray(input.loaders))
            throw new Error("You must provide an array of string values for 'loaders'.");

        // Check each array item is a string.
        input.loaders.forEach(function(loader) {
            if (!Utils.isString(loader))
                throw new Error("You must provide an array of string values for 'loaders'.");
        });
    }

    // Ensure the 'query' property is an object.
    if (Utils.isDefined(input.query) && !Utils.isObject(input.query))
        throw new Error("You must provide an object for 'query'.");

    // Ensure the 'queries' property is an object of objects.
    if (Utils.isDefined(input.queries)) {
        if (!Utils.isObject(input.queries))
            throw new Error("You must provide an object of objects for 'queries'.");

        // Check each array item is a string.
        Object.keys(input.queries).forEach(function(key) {
            if (!Utils.isObject(input.queries[key]))
                throw new Error("You must provide an object of objects for 'queries'.");
        });
    }

    return input;
}

function merge(config, changes, property, customizer) {
    var source = changes;

    // Handle 'changes' as a function.
    if (Utils.isFunction(changes))
        source = changes(config);

    // Ensure 'changes' resolves to an object.
    if (!Utils.isObject(source))
        throw new Error("You must provide an object or function (that returns an object) for 'changes'.");

    // Validate the resolved value of 'changes'.
    try {
        validate(source);
    } catch(err) {
        throw new Error("Invalid 'changes' value. " + err.message);
    }

    if (Utils.isDefined(property)) {
        if (!Utils.isString(property))
            throw new Error("You must provide a string value for 'property'.");

        // Wrap 'changes' within the property: e.g. {[property]: changes}.
        var wrapper = {};
        wrapper[property] = source;
        source = wrapper;
    }

    if (Utils.isDefined(customizer) && !Utils.isFunction(customizer))
        throw new Error("You must provide a function for 'customizer'.");

    Merge(config, source, customizer);
}

function set(config, changes, property) {

}

function resolve(config) {
    return DeepClone(config);
}

module.exports = function loader(input) {
    // Validate and clone the input.
    var config = DeepClone(validate(input));

    return {
        merge: function(property, changes, customizer) {
            var args = Array.prototype.slice.call(arguments);

            (function() {
                // Handle if no arguments are passed.
                if (!args.length)
                    throw new Error("You must provide either an object or function value for 'changes'.");

                // Handle when just changes are passed.
                // Note: This will either be an object or a function.
                if (args.length == 1)
                    return merge(config, property);

                // Handle when a property or customizer is passed.
                if (args.length == 2) {
                    // If the second parameter is a function, we assume they
                    // passed 'changes' and 'customizer'.
                    if (Utils.isFunction(changes))
                        return merge(config, property, undefined, changes);

                    // Assume they passed a 'property' and 'changes'.
                    return merge(config, changes, property);
                }

                // Handle when all arguments are passed.
                // Note: we ignore any other parameters.
                if (args.length >= 3)
                    return merge(config, changes, property, customizer);
            })();

            // Return 'this' to enable function chaining.<commit_msg>Removed the need to convert arguments to a real array.<commit_after>var Utils = require("./utilities");
var DeepClone = require("lodash.clonedeep");
var Merge = require("lodash.mergewith");

function validate(input) {
    // Check it's an object.
    if (!Utils.isObject(input))
        throw new Error("You must provide a loader config object.");

    // Ensure 'test', 'exclude', and 'include' properties are regex values.
    ["test", "exclude", "include"].forEach(function(property) {
        var value = input[property];

        if (Utils.isDefined(value) && !Utils.isRegex(value))
            throw new Error("You must provide a regex value for '" + property + "'.");
    });

    // Ensure the 'loader' property is a string.
    if (Utils.isDefined(input.loader) && !Utils.isString(input.loader))
        throw new Error("You must provide a string value for 'loader'.");

    // Ensure the 'loaders' property is an array of strings.
    if (Utils.isDefined(input.loaders)) {
        if (!Utils.isArray(input.loaders))
            throw new Error("You must provide an array of string values for 'loaders'.");

        // Check each array item is a string.
        input.loaders.forEach(function(loader) {
            if (!Utils.isString(loader))
                throw new Error("You must provide an array of string values for 'loaders'.");
        });
    }

    // Ensure the 'query' property is an object.
    if (Utils.isDefined(input.query) && !Utils.isObject(input.query))
        throw new Error("You must provide an object for 'query'.");

    // Ensure the 'queries' property is an object of objects.
    if (Utils.isDefined(input.queries)) {
        if (!Utils.isObject(input.queries))
            throw new Error("You must provide an object of objects for 'queries'.");

        // Check each array item is a string.
        Object.keys(input.queries).forEach(function(key) {
            if (!Utils.isObject(input.queries[key]))
                throw new Error("You must provide an object of objects for 'queries'.");
        });
    }

    return input;
}

function merge(config, changes, property, customizer) {
    var source = changes;

    // Handle 'changes' as a function.
    if (Utils.isFunction(changes))
        source = changes(config);

    // Ensure 'changes' resolves to an object.
    if (!Utils.isObject(source))
        throw new Error("You must provide an object or function (that returns an object) for 'changes'.");

    // Validate the resolved value of 'changes'.
    try {
        validate(source);
    } catch(err) {
        throw new Error("Invalid 'changes' value. " + err.message);
    }

    if (Utils.isDefined(property)) {
        if (!Utils.isString(property))
            throw new Error("You must provide a string value for 'property'.");

        // Wrap 'changes' within the property: e.g. {[property]: changes}.
        var wrapper = {};
        wrapper[property] = source;
        source = wrapper;
    }

    if (Utils.isDefined(customizer) && !Utils.isFunction(customizer))
        throw new Error("You must provide a function for 'customizer'.");

    Merge(config, source, customizer);
}

function set(config, changes, property) {

}

function resolve(config) {
    return DeepClone(config);
}

module.exports = function loader(input) {
    // Validate and clone the input.
    var config = DeepClone(validate(input));

    return {
        merge: function(property, changes, customizer) {
            var argsLength = arguments.length;

            (function() {
                // Handle if no arguments are passed.
                if (!argsLength)
                    throw new Error("You must provide either an object or function value for 'changes'.");

                // Handle when just changes are passed.
                // Note: This will either be an object or a function.
                if (argsLength == 1)
                    return merge(config, property);

                // Handle when a property or customizer is passed.
                if (argsLength == 2) {
                    // If the second parameter is a function, we assume they
                    // passed 'changes' and 'customizer'.
                    if (Utils.isFunction(changes))
                        return merge(config, property, undefined, changes);

                    // Assume they passed a 'property' and 'changes'.
                    return merge(config, changes, property);
                }

                // Handle when all arguments are passed.
                // Note: we ignore any other parameters.
                if (argsLength >= 3)
                    return merge(config, changes, property, customizer);
            })();

            // Return 'this' to enable function chaining.
{'fraction_non_alphanumeric': 0.11545761282159427, 'fraction_numerical': 0.0006326444538169548, 'mean_word_length': 2.156405990016639, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2040875', 'n_tokens_mistral': 2501, 'n_tokens_neox': 2416, 'n_words': 858}