0

Is there a JavaScript module that makes it easy to map arguments to parameters? Here is how I envision it working:

var arguments = assignArguments(arguments, 'p1', 'p2', [{'p3': 0}, 'p4'], {'p5': 'unknown'});

Within a function, you would call this to generate an object that associated a parameter with an argument. Parameters defined within an array or inline object would be considered optional, where inline objects would permit assigning default values. All other parameters are considered "required".

Here are some sample inputs/outpus:

foo(1): { p1: 1, p3: 0, p5: 'unknown' } // no p2 (aka undefined) 
foo(1, 2): { p1: 1, p2: 2, p3: 0, p5: 'unknown' } 
foo(1, 2, 3): { p1: 1, p2: 2, p3: 0, p4: 3, p5: 'unknown' } 
foo(1, 2, 3, 4): { p1: 1, p2: 2, p3: 3, p4: 4, p5: 'unknown' } 
foo(1, 2, 3, 4, 5): { p1: 1, p2: 2, p3: 3, p4: 4, p5: 5 }

I am hoping a library like this already exists. This logic gets repeated a lot and I want to eliminate it if possible.

Is anyone aware of a library like this? If not, can someone send me down the right path for implementing one?

Travis Parks
  • 8,435
  • 12
  • 52
  • 85

1 Answers1

0

I went ahead and thought of a way of doing this myself. It involves parsing an object graph made up of strings, arrays and objects. It's quite long, but it works well.

function assignArguments(values, expression) {              
    // determine how many arguments are needed for each parameter
    // grab all of the defaults, too
    var needed = 1;
    var argsNeeded = {};
    var defaults = {};
    var queue = [expression];               
    for (var queueIndex = 0; queueIndex < queue.length; ++queueIndex) {
        var node = queue[queueIndex];
        if (typeof node === 'string') {
            // the node is a required parameter
            argsNeeded[node] = needed;
            ++needed;
        } else if (node instanceof Array) {
            // the node is a list of parameters
            for (var index = 0; index !== node.length; ++index) {
                queue.push(node[index]);
            }
        } else {
            // the node is a list of optional parameters with defaults
            // make sure there isn't more than one parameter
            var count = 0;
            for (var key in node) {
                if (node.hasOwnProperty(key)) {
                    if (count !== 0) {
                        throw new Error('A default parameter list had more than one value.');
                    }
                    defaults[key] = node[key];
                    queue.push(key);
                    ++count;
                }
            }
        }
    }

    // determine the order that the parameters appear
    var parameters = [];
    var stack = [expression];
    while (stack.length > 0) {
        var node = stack.pop();
        if (typeof node === 'string') {
            // the node is a required parameter
            parameters.push(node);
        } else if (node instanceof Array) {
            // the node is a list of parameters
            var index = node.length;
            while (index !== 0) {
                --index;
                stack.push(node[index]);
            }
        } else {
            // the node is an optional parameter with defaults
            // we'll check for multiple parameters
            var count = 0;
            for (var key in node) {
                if (node.hasOwnProperty(key)) {
                    if (count > 0) {
                        throw new Error('A default parameter list had more than one value.');
                    }
                    stack.push(key);
                    ++count;
                }
            }
        }
    }

    var result = {};
    var valueIndex = 0;
    for (var index = 0; index !== parameters.length; ++index) {
        var parameter = parameters[index];
        var needed = argsNeeded[parameter];
        if (needed > values.length) {
            if (parameter in defaults) {
                result[parameter] = defaults[parameter];
            }
        } else {
            result[parameter] = values[valueIndex];
            ++valueIndex;
        }
    }

    return result;
}

And here is an example using it.

function foo() {
    var params = assignArguments(arguments, ['p1', 'p2', [{p3:0}, 'p4'], {p5: 'unknown'}]);
    return params;
}

console.log(foo(1));
console.log(foo(1, 2));
console.log(foo(1, 2, 3));
console.log(foo(1, 2, 3, 4));
console.log(foo(1, 2, 3, 4, 5));
Travis Parks
  • 8,435
  • 12
  • 52
  • 85