Code coverage report for lib/utils.js

Statements: 70.73% (58 / 82)      Branches: 53.49% (23 / 43)      Functions: 89.47% (17 / 19)      Lines: 73.42% (58 / 79)      Ignored: none     

All files » lib/ » utils.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 1811 1 1 1 1   1 6 6     1                                         816     816               951       870 870 870         870                     858       3846 3846 3884 8388     3846               1240       1070 1072       1070 10   1070               823 823   823     823 823 18602       823 823 20044       823 17779 418623 34716   383907             823       797 797                             2029 2029 17147 2029             440 440 54   440       361 361 1008 776     361      
var shim = require('./shim');
var forEach = shim.forEach;
var filter = shim.filter;
var reduce = shim.reduce;
var getKeys = shim.getKeys;
 
var errorMethodBlacklist = reduce(['message', 'line', 'sourceId', 'sourceURL', 'stack', 'stackArray'], function (result, prop) {
    result[prop] = true;
    return result;
}, {});
 
module.exports = {
    // https://gist.github.com/1044128/
    getOuterHTML: function (element) {
        // jshint browser:true
        if ('outerHTML' in element) return element.outerHTML;
        var ns = "http://www.w3.org/1999/xhtml";
        var container = document.createElementNS(ns, '_');
        var xmlSerializer = new XMLSerializer();
        var html;
        if (document.xmlVersion) {
            return xmlSerializer.serializeToString(element);
        } else {
            container.appendChild(element.cloneNode(false));
            html = container.innerHTML.replace('><', '>' + element.innerHTML + '<');
            container.innerHTML = '';
            return html;
        }
    },
 
    // Returns true if object is a DOM element.
    isDOMElement: function (object) {
        Iif (typeof HTMLElement === 'object') {
            return object instanceof HTMLElement;
        } else {
            return object &&
                typeof object === 'object' &&
                object.nodeType === 1 &&
                typeof object.nodeName === 'string';
        }
    },
 
    isArray: function (ar) {
        return Object.prototype.toString.call(ar) === '[object Array]';
    },
 
    isRegExp: function (re) {
        var s;
        try {
            s = '' + re;
        } catch (e) {
            return false;
        }
 
        return re instanceof RegExp || // easy case
        // duck-type for context-switching evalcx case
        typeof(re) === 'function' &&
            re.constructor.name === 'RegExp' &&
            re.compile &&
            re.test &&
            re.exec &&
            s.match(/^\/.*\/[gim]{0,3}$/);
    },
 
    isError: function (err) {
        return typeof err === 'object' && Object.prototype.toString.call(err) === '[object Error]';
    },
 
    extend: function (target) {
        var sources = Array.prototype.slice.call(arguments, 1);
        forEach(sources, function (source) {
            forEach(getKeys(source), function (key) {
                target[key] = source[key];
            });
        });
        return target;
    },
 
    isUndefinedOrNull: function (value) {
        return value === null || value === undefined;
    },
 
    isArguments: function (object) {
        return Object.prototype.toString.call(object) === '[object Arguments]';
    },
 
    getKeysOfDefinedProperties: function (object) {
        var keys = filter(getKeys(object), function (key) {
            return typeof object[key] !== 'undefined';
        });
        // The 'message' property of Error instances is enumerable for some reason, but we want
        // to include it in the set when comparing:
        if (Object.prototype.toString.call(object) === '[object Error]') {
            keys.push('message');
        }
        return keys;
    },
 
    /**
     * Levenshtein distance algorithm from wikipedia
     * http://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#JavaScript
     */
    levenshteinDistance: function (a, b) {
        Iif (a.length === 0) return b.length;
        Iif (b.length === 0) return a.length;
 
        var matrix = [];
 
        // increment along the first column of each row
        var i;
        for (i = 0; i <= b.length; i += 1) {
            matrix[i] = [i];
        }
 
        // increment each column in the first row
        var j;
        for (j = 0; j <= a.length; j += 1) {
            matrix[0][j] = j;
        }
 
        // Fill in the rest of the matrix
        for (i = 1; i <= b.length; i += 1) {
            for (j = 1; j <= a.length; j += 1) {
                if (b.charAt(i - 1) === a.charAt(j - 1)) {
                    matrix[i][j] = matrix[i - 1][j - 1];
                } else {
                    matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, // substitution
                                            Math.min(matrix[i][j - 1] + 1, // insertion
                                                     matrix[i - 1][j] + 1)); // deletion
                }
            }
        }
 
        return matrix[b.length][a.length];
    },
 
    truncateStack: function (err, fn) {
        Eif (Error.captureStackTrace) {
            Error.captureStackTrace(err, fn);
        } else if ('stack' in err) {
            // Excludes IE<10, and fn cannot be anonymous for this backup plan to work:
            var stackEntries = err.stack.split(/\r\n?|\n\r?/),
            needle = 'at ' + fn.name + ' ';
            for (var i = 0 ; i < stackEntries.length ; i += 1) {
                if (stackEntries[i].indexOf(needle) !== -1) {
                    stackEntries.splice(1, i);
                    err.stack = stackEntries.join("\n");
                }
            }
        }
    },
 
    findFirst: function (arr, predicate, thisObj) {
        var scope = thisObj || null;
        for (var i = 0 ; i < arr.length ; i += 1) {
            if (predicate.call(scope, arr[i], i, arr)) {
                return arr[i];
            }
        }
        return null;
    },
 
    leftPad: function (str, width, ch) {
        ch = ch || ' ';
        while (str.length < width) {
            str = ch + str;
        }
        return str;
    },
 
    cloneError: function (e) {
        var newError = new Error();
        forEach(getKeys(e), function (key) {
            if (!errorMethodBlacklist[key]) {
                newError[key] = e[key];
            }
        });
        return newError;
    }
};