%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /proc/985914/root/data/old/home/stash/atlassian-stash/static/util/
Upload File :
Create Path :
Current File : //proc/985914/root/data/old/home/stash/atlassian-stash/static/util/function.js

define('util/function', [
    'underscore',
    'exports'
],
/**
 * Functional programming utils
 *
 * @exports util/function
 */
function(
    _,
    exports
    ) {

    'use strict';

    var slice = Array.prototype.slice;

    /**
     * Takes any number of predicate functions and returns a function that returns true if all the predicates return true
     *
     * @param {...Function} predicates - The predicate functions to combine
     *
     * @example
     * var isPositive = function(a){ return a > 0; }
     * var isEven = function(a){ return a % 2 === 0; }
     * var isPositiveAndEven = and(isPositive, isEven)
     *
     * isPositiveAndEven(2)     // => true
     * isPositiveAndEven(1)     // => false
     * isPositiveAndEven(-2)    // => false
     *
     * @returns {Function}
     */
    function and(/*predicates*/){
        var predicates = slice.call(arguments);

        return function(/*arguments*/){
            return _(predicates).every(lazyApply(arguments));
        };
    }


    /**
     * Invokes a list of functions with a given set of arguments.
     *
     * @param {Array<function>} list - list of functions
     * @param {Array} args - list of arguments to apply
     * @returns {Array} the results of applying args to each function
     */
    function applyAll(list, args) {
        return _.map(list, lazyApply.call(this, args));
    }

    /**
     * Limit the number of arguments passed to a function.
     * Used to trim off extra arguments from collection methods like `map` and `forEach`
     * @param {Function} fn
     * @param {number} numArgs
     *
     * @example
     *     fn.arity(function(){return arguments}, 2)(1,2,3) // => [1, 2]
     *
     * @returns {Function}
     */
    function arity(fn, numArgs) {
        return function(){
            return fn.apply(this, slice.call(arguments, 0, numArgs));
        };
    }

    /**
     * Returned a function that when called _always_ returns the original argument.
     * @param {*} arg
     *
     * @example
     * _.map(['a', 'b', 'c'], fn.constant('x')) // => ['x', 'x', 'x']
     *
     * @returns {Function}
     */
    function constant(arg) {
        return function() {
            return arg;
        };
    }

    /**
     * Return a function that when called with argument A, will return a default value if A is undefined or null, otherwise
     * will return A.
     * @param {*} theDefault
     *
     * @example
     * _.map(['foo', 'bar', null, 'bar'], fn.defaultValue('foo')) // => ['foo', 'bar', 'foo', 'bar']
     *
     * @returns {Function}
     */
    function defaultValue(theDefault) {
        return function(a) {
            return a != null ? a : theDefault;
        };
    }

    /**
     * Get a property from a lazy object.
     * Basically a more generic version of _.pluck.
     * Supports '.' separated keypaths e.g. 'user.avatar.size'
     * Has null safety for keypaths (will return undefined if the keypath is invalid rather than throwing an exception)
     * @param {string} keyPath
     *
     * @example
     * var values = [{a: 'b'}, {a: 'c'}]
     *
     * _.map(values, fn.dot('a')) //=> ['b', 'c']
     * _.map(values, _.compose(fn.eq('b'), fn.dot('a'))) // => [true, false]
     *
     *
     * var obj = { my: { nested : { prop : 'foo' } } };
     * dot('my.nested.prop')(obj)    // => 'foo'
     * dot('my.invalid.prop')(obj)   // => undefined //invalid key path
     *
     * @returns {Function}
     */
    function dot(keyPath) {
        var keyParts = keyPath.split('.');
        return function(object) {
            return _(keyParts).reduce(function(obj, propName) {
                return (obj != null) ? obj[propName] : undefined;
            }, object);
        };
    }

    /**
     * Similar to invoke, but whereas invoke explicitly calls a function and returns undefined if the property is not one,
     * dotX says that if the matched property is a function, eXecute it (with supplied args), otherwise return the property
     * Basically a conditional dot + invoke
     * Supports keypaths with null safety
     *
     * @param {string} keyPath
     *
     * @example
     * dotX('myFunc')({myFunc: fn.constant('foo')})  // => 'foo'
     *
     * var obj = { my: { nested : { prop1 : 'foo', prop2: fn.constant('bar') } } };
     * dotX('my.nested.prop1')(obj)  // => 'foo'
     * dotX('my.nested.prop2')(obj)  // => 'bar'
     * dotX('my.invalid.prop')(obj)  // => undefined //invalid key path
     *
     * @returns {Function}
     */
    function dotX(keyPath/*, args*/) {
        var args = slice.call(arguments, 1);

        return function(object) {
            var prop = dot(keyPath)(object);

            return (typeof prop === 'function') ? prop.apply(object, args) : prop;
        };
    }

    /**
     * Curried form of strict equals.
     * @param {*} a
     *
     * @example
     * _.map(['a', 'b', 'c'], fn.eq('a')) // => [true, false, false]
     *
     * @returns {Function}
     */
    function eq(a) {
        return function(b) {
            return a === b;
        };
    }

    /**
     * Reverses the order of the function parameters
     * @param {Function} fn
     *
     * @example
     * fn.flip(function(){return arguments})(1,2,3) //=> [3, 2, 1]
     *
     * @returns {Function}
     */
    function flip(fn) {
        return function() {
            return fn.apply(this, slice.call(arguments).reverse());
        };
    }

    /**
     * Wrapper for an `indexOf` type function that converts the result into a `found` boolean
     *
     * @param {Function} fn
     *
     * var myArray = [1,2,3,4];
     * var foundInArray = found(myArray.indexOf.bind(myArray));
     * foundInArray(1) // => true
     * foundInArray(4) // => true
     * foundInArray(5) // => false
     *
     * @returns {Function}
     */
    function found(fn){
        return function(/*arguments*/) {
            var index = fn.apply(this, arguments);

            return index >= 0;
        };
    }

    /**
     * Curried form of _.invoke that works with a single object.
     * Useful when you are mapping over a collection and you want to call a method on each object that returns a value.
     * Similar to `.map('.method')` in Bacon.
     * Explicitly requires that the property is a function or throws a type error
     * Also supports keypaths with null safety like fn.dot, however as mentioned above, if the final output of the
     * keypath is undefined, invoke will throw a type error.
     *
     * @param {string} methodPath
     *
     * @example
     * _.map([{isTrue: fn.constant(false)}, {isTrue: fn.constant(true)}], fn.invoke('isTrue')) // => [false, true]
     *
     * invoke('some.nested.prop')({some:{nested: {prop: fn.constant('bar')}}}) // => 'bar'
     * invoke('some.nested.prop')({some:{nested: {prop: 'bar'}}}) // => Throws TypeError
     * invoke('some.invalid.prop')({some:{nested: {prop: fn.constant('bar')}}}) // => Throws TypeError
     *
     * @returns {Function}
     */
    function invoke(methodPath/*, args*/) {
        var args = slice.call(arguments, 1);

        return function(object) {
            var fn = dot(methodPath)(object);

            if (typeof fn !== 'function') {
                throw new TypeError(fn + ' is not a function');
            }

            return fn.apply(object, args);
        };
    }

    /**
     * Returns a function that will apply the arguments to another function that is passed in.
     * The use-case is usually related to mapping over a list of functions.
     *
     * @param {Array} args - array of arguments to apply
     * @returns {Function}
     */
    function lazyApply(args) {
        return function(f) {
            // Function.prototype.apply.call should work, but doesn't. :(
            return f.apply(this, args);
        };
    }

    /**
     * The inverse of {@link dot}. Takes an object and returns a function for looking up keys in that object.
     * @param {Object} map - object to lookup properties within.
     *
     * @example
     * var myObj = {foo: 'bar', x:'y'};
     *
     * _.map(['foo', 'x'], lookup(myObj)) //=> ['bar', 'y']
     *
     * @returns {Function}
     */
    function lookup(map) {
        return function(key) {
            return map[key];
        };
    }

    /**
     * Curries the application of any function to `!` and some arguments.
     * In other words lazily inverts any function.
     * @param {Function} fn
     *
     * @example
     * _.map(['a', 'b', 'c'], fn.not(fn.eq('a'))) //=> [false, true, true]
     *
     * @returns {Function}
     */
    function not(fn) {
        return function(/*arguments*/) {
            return !fn.apply(this, arguments);
        };
    }

    /**
     * Takes any number of predicate functions and returns a function that returns true if any of the predicates return true
     *
     * @param {...Function} predicates - The predicate functions to combine
     *
     * @example
     * var isPositive = function(a){ return a > 0; }
     * var isEven = function(a){ return a % 2 === 0; }
     * var isPositiveOrEven = or(isPositive, isEven)
     *
     * isPositiveOrEven(2)     // => true
     * isPositiveOrEven(1)     // => true
     * isPositiveOrEven(-2)    // => true
     * isPositiveOrEven(-1)    // => false
     *
     * @returns {Function}
     */
    function or(/*predicates*/){
        var predicates = slice.call(arguments);

        return function(/*arguments*/){
            return _(predicates).some(lazyApply(arguments));
        };
    }

    /**
     * Partially apply from the right rather than the left
     * @param {Function} fn
     *
     * @example
     * fn.partialRight(function(){return arguments}, 3, 4)(1, 2) //=> [1, 2, 3, 4]
     *
     * @returns {Function}
     */
    function partialRight(fn /*, arguments*/) {
        var partialArgs = slice.call(arguments, 1);

        return function(){
            return fn.apply(this, slice.call(arguments).concat(partialArgs));
        };
    }

    /**
     * Return a function that will call the passed function with one of the incoming arguments spread out (if it's an array).
     * @param {Function} intoFn - the function to call with spread arguments
     * @param {number} [index=0] - the index of the parameter to spread
     *
     * @example
     * var varFunc = spread(func, 2);
     *
     * varFunc(1,2,[3,4],5) === func(1,2,3,4,5)
     * varFunc(1,2,3,4,5) === func(1,2,3,4,5)
     *
     * @returns {Function}
     */
    function spread(intoFn, index) {
        return function() {
            if (arguments.length <= index) {
                return intoFn.apply(this, arguments);
            }

            // arguments.splice(index, 1, ...arguments[index])
            var args = slice.call(arguments);
            args.splice.apply(args, [index || 0, 1].concat(args[ index || 0]));

            return intoFn.apply(this, args);
        };
    }

    /**
     * Map the context of a function call to a param.
     * Mainly used for jQuery which sticks the target element in `this` for callbacks.
     * This way you can `.bind` the callback to a different scope and still have easy access to the target element.
     * It also makes it easier to reuse API methods as handlers.
     * `fn` will be called with `this` as the first param, then the rest of the original arguments
     * @param {Function} fn
     *
     * @example
     * $(document).click(fn.thisToParam(function(){console.log(arguments)})) //=> [document, jQuery.Event]
     *
     * @returns {Function}
     */
    function thisToParam(fn){
        return function(/*arguments*/){
            var args = slice.call(arguments);
            args.unshift(this);
            return fn.apply(this, args);
        };
    }

    exports.and = and;
    exports.applyAll = applyAll;
    exports.arity = arity;
    exports.constant = constant;
    exports.defaultValue = defaultValue;
    exports.dot = dot;
    exports.dotX = dotX;
    exports.eq = eq;
    exports.flip = flip;
    exports.found = found;
    exports.invoke = invoke;
    exports.lookup = lookup;
    exports.lazyApply = lazyApply;
    exports.not = not;
    exports.or = or;
    exports.partialRight = partialRight;
    exports.spread = spread;
    exports.thisToParam = thisToParam;
    exports.unary = partialRight(arity, 1);
    exports.binary = partialRight(arity, 2);
});

Zerion Mini Shell 1.0