diff options
Diffstat (limited to 'utils/lib/util.js')
-rwxr-xr-x | utils/lib/util.js | 864 |
1 files changed, 0 insertions, 864 deletions
diff --git a/utils/lib/util.js b/utils/lib/util.js deleted file mode 100755 index 510e322..0000000 --- a/utils/lib/util.js +++ /dev/null @@ -1,864 +0,0 @@ - -// a decorator for functions that curry "polymorphically", -// that is, that return a function that can be tested -// against various objects if they're only "partially -// completed", or fewer arguments than needed are used. -// -// this enables the idioms: -// [1, 2, 3].every(lt(4)) eq true -// [1, 2, 3].map(add(1)) eq [2, 3, 4] -// [{}, {}, {}].forEach(set('a', 10)) -// -exports.operator = function (name, length, block) { - var operator = function () { - var args = exports.array(arguments); - var completion = function (object) { - if ( - typeof object == "object" && - object !== null && // seriously? typeof null == "object" - name in object && // would throw if object === null - // not interested in literal objects: - !Object.prototype.hasOwnProperty.call(object, name) - ) - return object[name].apply(object, args); - return block.apply( - this, - [object].concat(args) - ); - }; - if (arguments.length < length) { - // polymoprhic curry, delayed completion - return completion; - } else { - // immediate completion - return completion.call(this, args.shift()); - } - }; - operator.name = name; - operator.displayName = name; - operator.length = length; - operator.operator = block; - return operator; -}; - -exports.no = function (value) { - return value === null || value === undefined; -}; - -// object - -exports.object = exports.operator('object', 1, function (object) { - var items = object; - if (!items.length) - items = exports.items(object); - var copy = {}; - for (var i = 0; i < items.length; i++) { - var item = items[i]; - var key = item[0]; - var value = item[1]; - copy[key] = value; - } - return copy; -}); - -exports.object.copy = function (object) { - var copy = {}; - exports.object.keys(object).forEach(function (key) { - copy[key] = object[key]; - }); - return copy; -}; - -exports.object.deepCopy = function (object) { - var copy = {}; - exports.object.keys(object).forEach(function (key) { - copy[key] = exports.deepCopy(object[key]); - }); - return copy; -}; - -exports.object.eq = function (a, b, stack) { - return ( - !exports.no(a) && !exports.no(b) && - exports.array.eq( - exports.sort(exports.object.keys(a)), - exports.sort(exports.object.keys(b)) - ) && - exports.object.keys(a).every(function (key) { - return exports.eq(a[key], b[key], stack); - }) - ); -}; - -exports.object.len = function (object) { - return exports.object.keys(object).length; -}; - -exports.object.has = function (object, key) { - return Object.prototype.hasOwnProperty.call(object, key); -}; - -exports.object.keys = function (object) { - var keys = []; - for (var key in object) { - if (exports.object.has(object, key)) - keys.push(key); - } - return keys; -}; - -exports.object.values = function (object) { - var values = []; - exports.object.keys(object).forEach(function (key) { - values.push(object[key]); - }); - return values; -}; - -exports.object.items = function (object) { - var items = []; - exports.object.keys(object).forEach(function (key) { - items.push([key, object[key]]); - }); - return items; -}; - -exports.object.update = function (target, source) { - for (var key in source) { - if (exports.object.has(source, key)) { - target[key] = source[key]; - } - } -}; - -exports.object.complete = function (target, source) { - for (var key in source) { - if ( - exports.object.has(source, key) && - !exports.object.has(target, key) - ) { - target[key] = source[key]; - } - } -}; - -exports.object.repr = function (object) { - return "{" + - exports.object.keys(object) - .map(function (key) { - return exports.enquote(key) + ": " + - exports.repr(object[key]); - }).join(", ") + - "}"; -}; - -// array - -exports.array = function (array) { - if (!exports.isArrayLike(array)) - return exports.items(array); - return Array.prototype.slice.call(array); -}; - -exports.isArrayLike = function(object) { - return object && - typeof object === "object" && - ( - object.constructor === Array || - typeof object.callee !== "undefined" - ); -}; - -exports.array.copy = exports.array; - -exports.array.deepCopy = function (array) { - return array.map(exports.deepCopy); -}; - -exports.array.len = function (array) { - return array.length; -}; - -exports.array.has = function (array, value) { - return Array.prototype.indexOf.call(array, value) >= 0; -}; - -exports.array.put = function (array, key, value) { - array.splice(key, 0, value); - return array; -}; - -exports.array.del = function (array, begin, end) { - array.splice(begin, end === undefined ? 1 : (end - begin)); - return array; -}; - -exports.array.eq = function (a, b, stack) { - return exports.isArrayLike(b) && - a.length == b.length && - exports.zip(a, b).every(exports.apply(function (a, b) { - return exports.eq(a, b, stack); - })); -}; - -exports.array.lt = function (a, b) { - var length = Math.max(a.length, b.length); - for (var i = 0; i < length; i++) - if (!exports.eq(a[i], b[i])) - return exports.lt(a[i], b[i]); - return false; -}; - -exports.array.repr = function (array) { - return "[" + exports.map(array, exports.repr).join(', ') + "]"; -}; - -exports.apply = exports.operator('apply', 2, function (args, block) { - return block.apply(this, args); -}); - -exports.copy = exports.operator('copy', 1, function (object) { - if (exports.no(object)) - return object; - if (exports.isArrayLike(object)) - return exports.array.copy(object); - if (typeof object == 'object') - return exports.object.copy(object); - return object; -}); - -exports.deepCopy = exports.operator('deepCopy', 1, function (object) { - if (exports.no(object)) - return object; - if (exports.isArrayLike(object)) - return exports.array.deepCopy(object); - if (typeof object == 'object') - return exports.object.deepCopy(object); - return object; -}); - -exports.repr = exports.operator('repr', 1, function (object) { - if (exports.no(object)) - return String(object); - if (exports.isArrayLike(object)) - return exports.array.repr(object); - if (typeof object == 'object') - return exports.object.repr(object); - if (typeof object == 'string') - return exports.enquote(object); - return object.toString(); -}); - -exports.keys = exports.operator('keys', 1, function (object) { - if (exports.isArrayLike(object)) - return exports.range(object.length); - else if (typeof object == 'object') - return exports.object.keys(object); - return []; -}); - -exports.values = exports.operator('values', 1, function (object) { - if (exports.isArrayLike(object)) - return exports.array(object); - else if (typeof object == 'object') - return exports.object.values(object); - return []; -}); - -exports.items = exports.operator('items', 1, function (object) { - if (exports.isArrayLike(object) || typeof object == "string") - return exports.enumerate(object); - else if (typeof object == 'object') - return exports.object.items(object); - return []; -}); - -exports.len = exports.operator('len', 1, function (object) { - if (exports.isArrayLike(object)) - return exports.array.len(object); - else if (typeof object == 'object') - return exports.object.len(object); -}); - -exports.has = exports.operator('has', 2, function (object, value) { - if (exports.isArrayLike(object)) - return exports.array.has(object, value); - else if (typeof object == 'object') - return exports.object.has(object, value); - return false; -}); - -exports.get = exports.operator('get', 2, function (object, key, value) { - if (typeof object == "string") { - if (!typeof key == "number") - throw new Error("TypeError: String keys must be numbers"); - if (!exports.has(exports.range(object.length), key)) { - if (arguments.length == 3) - return value; - throw new Error("KeyError: " + exports.repr(key)); - } - return items.charAt(object); - } - if (typeof object == "object") { - if (!exports.object.has(object, key)) { - if (arguments.length == 3) - return value; - throw new Error("KeyError: " + exports.repr(key)); - } - return object[key]; - } - throw new Error("Object does not have keys: " + exports.repr(object)); -}); - -exports.set = exports.operator('set', 3, function (object, key, value) { - object[key] = value; - return object; -}); - -exports.getset = exports.operator('getset', 3, function (object, key, value) { - if (!exports.has(object, key)) - exports.set(object, key, value); - return exports.get(object, key); -}); - -exports.del = exports.operator('del', 2, function (object, begin, end) { - if (exports.isArrayLike(object)) - return exports.array.del(object, begin, end); - delete object[begin]; - return object; -}); - -exports.cut = exports.operator('cut', 2, function (object, key) { - var result = exports.get(object, key); - exports.del(object, key); - return result; -}); - -exports.put = exports.operator('put', 2, function (object, key, value) { - if (exports.isArrayLike(object)) - return exports.array.put(object, key, value); - return exports.set(object, key, value); -}); - -exports.update = exports.operator('update', 2, function (target, source) { - exports.object.update(target, source); -}); - -exports.complete = exports.operator('complete', 2, function (target, source) { - exports.object.complete(target, source); -}); - -// TODO insert -// TODO remove -// TODO discard - -exports.range = function () { - var start = 0, stop = 0, step = 1; - if (arguments.length == 1) { - stop = arguments[0]; - } else if (arguments.length == 2) { - start = arguments[0]; - stop = arguments[1]; - } else if (arguments.length == 3) { - start = arguments[0]; - stop = arguments[1]; - step = arguments[2]; - } - var range = []; - for (var i = start; i < stop; i += step) - range.push(i); - return range; -}; - -exports.forEach = function (array, block) { - Array.prototype.forEach.call(array, block); -}; - -exports.forEachApply = function (array, block) { - Array.prototype.forEach.call(array, exports.apply(block)); -}; - -exports.map = function (array, block, context) { - return Array.prototype.map.call(array, block, context); -}; - -exports.mapApply = function (array, block) { - return Array.prototype.map.call(array, exports.apply(block)); -}; - -exports.every = exports.operator('every', 2, function (array, block, context) { - return exports.all(exports.map(array, block, context)); -}); - -exports.some = exports.operator('some', 2, function (array, block, context) { - return exports.any(exports.map(array, block, context)); -}); - -exports.all = exports.operator('all', 1, function (array) { - for (var i = 0; i < array.length; i++) - if (!array[i]) - return false; - return true; -}); - -exports.any = exports.operator('all', 1, function (array) { - for (var i = 0; i < array.length; i++) - if (array[i]) - return true; - return false; -}); - -exports.reduce = exports.operator('reduce', 2, function (array, block, basis) { - return array.reduce.apply(array, arguments); -}); - -exports.reduceRight = exports.operator('reduceRight', 2, function (array, block, basis) { - return array.reduceRight.apply(array, arguments); -}); - -exports.zip = function () { - return exports.transpose(arguments); -}; - -exports.transpose = function (array) { - var transpose = []; - for (var i = 0; i < array.length; i++) { - var row = array[i]; - for (var j = 0; j < row.length; j++) { - var cell = row[j]; - if (!transpose[j]) - transpose[j] = []; - transpose[j][i] = cell; - } - } - return transpose; -}; - -exports.enumerate = function (array, start) { - if (exports.no(start)) - start = 0; - return exports.zip( - exports.range(start, start + array.length), - array - ); -}; - -// arithmetic, transitive, and logical operators - -exports.is = function (a, b) { - return a === b; -}; - -exports.eq = exports.operator('eq', 2, function (a, b, stack) { - if (!stack) - stack = []; - if (a === b) - return true; - if (typeof a !== typeof b) - return false; - if (exports.no(a)) - return exports.no(b); - if (typeof a == "date") - return a.valueOf() == b.valueOf(); - if (typeof a == "regexp") - return a.source == b.source && - a.global == b.global && - a.ignoreCase == b.ignoreCase && - a.multiline == b.multiline; - if (typeof a == "function") { - var caller = stack[stack.length - 1]; - return caller !== Object && - typeof caller != "undefined"; - } - if (exports.isArrayLike(a)) - return exports.array.eq( - a, b, - stack.concat([a.constructor]) - ); - if (typeof a == 'object') - return exports.object.eq( - a, b, - stack.concat([a.constructor]) - ); - return a == b; -}); - -exports.ne = exports.operator('ne', 2, function (a, b) { - return !exports.eq(a, b); -}); - -exports.lt = exports.operator('lt', 2, function (a, b) { - if (exports.no(a) != exports.no(b)) - return exports.no(a) > exports.no(b); - if (exports.isArrayLike(a) && exports.isArrayLike(b)) - return exports.array.lt(a, b); - return a < b; -}); - -exports.gt = exports.operator('gt', 2, function (a, b) { - return !(exports.lt(a, b) || exports.eq(a, b)); -}); - -exports.le = exports.operator(2, 'le', function (a, b) { - return exports.lt(a, b) || exports.eq(a, b); -}); - -exports.ge = exports.operator(2, 'ge', function (a, b) { - return !exports.lt(a, b); -}); - -/*** by - returns a `comparator` that compares - values based on the values resultant from - a given `relation`. - accepts a `relation` and an optional comparator. - - To sort a list of objects based on their - "a" key:: - - objects.sort(by(get("a"))) - - To get those in descending order:: - - objects.sort(by(get("a")), desc) - - `by` returns a comparison function that also tracks - the arguments you used to construct it. This permits - `sort` and `sorted` to perform a Schwartzian transform - which can increase the performance of the sort - by a factor of 2. -*/ -exports.by = function (relation) { - var compare = arguments[1]; - if (exports.no(compare)) - compare = exports.compare; - var comparator = function (a, b) { - a = relation(a); - b = relation(b); - return compare(a, b); - }; - comparator.by = relation; - comparator.compare = compare; - return comparator; -}; - -exports.compare = exports.operator(2, 'compare', function (a, b) { - if (exports.no(a) != exports.no(b)) - return exports.no(b) - exports.no(a); - if (typeof a == "number" && typeof b == "number") - return a - b; - return exports.eq(a, b) ? 0 : exports.lt(a, b) ? -1 : 1; -}); - -/*** sort - an in-place array sorter that uses a deep comparison - function by default (compare), and improves performance if - you provide a comparator returned by "by", using a - Schwartzian transform. -*/ -exports.sort = function (array, compare) { - if (exports.no(compare)) - compare = exports.compare; - if (compare.by) { - /* schwartzian transform */ - array.splice.apply( - array, - [0, array.length].concat( - array.map(function (value) { - return [compare.by(value), value]; - }).sort(function (a, b) { - return exports.compare(a[0], b[0]); - }).map(function (pair) { - return pair[1]; - }) - ) - ); - } else { - array.sort(compare); - } - return array; -}; - -/*** sorted - returns a sorted copy of an array using a deep - comparison function by default (compare), and - improves performance if you provide a comparator - returned by "by", using a Schwartzian transform. -*/ -exports.sorted = function (array, compare) { - return exports.sort(exports.array.copy(array), compare); -}; - -// string - -/*** escape - escapes all characters of a string that are - special to JavaScript and many other languages. - Recognizes all of the relevant - control characters and formats all other - non-printable characters as Hex byte escape - sequences or Unicode escape sequences depending - on their size. - - Pass ``true`` as an optional second argument and - ``escape`` produces valid contents for escaped - JSON strings, wherein non-printable-characters are - all escaped with the Unicode ``\u`` notation. -*/ -/* more Steve Levithan flagrence */ -var escapeExpression = /[^ !#-[\]-~]/g; -/* from Doug Crockford's JSON library */ -var escapePatterns = { - '\b': '\\b', '\t': '\\t', - '\n': '\\n', '\f': '\\f', '\r': '\\r', - '"' : '\\"', '\\': '\\\\' -}; -exports.escape = function (value, strictJson) { - if (typeof value != "string") - throw new Error( - module.path + - "#escape: requires a string. got " + - exports.repr(value) - ); - return value.replace( - escapeExpression, - function (match) { - if (escapePatterns[match]) - return escapePatterns[match]; - match = match.charCodeAt(); - if (!strictJson && match < 256) - return "\\x" + exports.padBegin(match.toString(16), 2); - return '\\u' + exports.padBegin(match.toString(16), 4); - } - ); -}; - -/*** enquote - transforms a string into a string literal, escaping - all characters of a string that are special to - JavaScript and and some other languages. - - ``enquote`` uses double quotes to be JSON compatible. - - Pass ``true`` as an optional second argument to - be strictly JSON compliant, wherein all - non-printable-characters are represented with - Unicode escape sequences. -*/ -exports.enquote = function (value, strictJson) { - return '"' + exports.escape(value, strictJson) + '"'; -}; - -/*** expand - transforms tabs to an equivalent number of spaces. -*/ -// TODO special case for \r if it ever matters -exports.expand = function (str, tabLength) { - str = String(str); - tabLength = tabLength || 4; - var output = [], - tabLf = /[\t\n]/g, - lastLastIndex = 0, - lastLfIndex = 0, - charsAddedThisLine = 0, - tabOffset, match; - while (match = tabLf.exec(str)) { - if (match[0] == "\t") { - tabOffset = ( - tabLength - 1 - - ( - (match.index - lastLfIndex) + - charsAddedThisLine - ) % tabLength - ); - charsAddedThisLine += tabOffset; - output.push( - str.slice(lastLastIndex, match.index) + - operator.mul(" ", tabOffset + 1) - ); - } else if (match[0] === "\n") { - output.push(str.slice(lastLastIndex, tabLf.lastIndex)); - lastLfIndex = tabLf.lastIndex; - charsAddedThisLine = 0; - } - lastLastIndex = tabLf.lastIndex; - } - return output.join("") + str.slice(lastLastIndex); -}; - -var trimBeginExpression = /^\s\s*/g; -exports.trimBegin = function (value) { - return String(value).replace(trimBeginExpression, ""); -}; - -var trimEndExpression = /\s\s*$/g; -exports.trimEnd = function (value) { - return String(value).replace(trimEndExpression, ""); -}; - -exports.trim = function (value) { - return String(value).replace(trimBeginExpression, "").replace(trimEndExpression, ""); -}; - -/* generates padBegin and padEnd */ -var augmentor = function (augment) { - return function (value, length, pad) { - if (exports.no(pad)) pad = '0'; - if (exports.no(length)) length = 2; - value = String(value); - while (value.length < length) { - value = augment(value, pad); - } - return value; - }; -}; - -/*** padBegin - - accepts: - - a `String` or `Number` value - - a minimum length of the resultant `String`: - by default, 2 - - a pad string: by default, ``'0'``. - - returns a `String` of the value padded up to at least - the minimum length. adds the padding to the begining - side of the `String`. - -*/ -exports.padBegin = augmentor(function (value, pad) { - return pad + value; -}); - -/*** padEnd - - accepts: - - a `String` or `Number` value - - a minimum length of the resultant `String`: - by default, 2 - - a pad string: by default, ``'0'``. - - returns a `String` of the value padded up to at least - the minimum length. adds the padding to the end - side of the `String`. - -*/ -exports.padEnd = augmentor(function (value, pad) { - return value + pad; -}); - -/*** splitName - splits a string into a `List` of words from an origin - string. -*/ -var splitNameExpression = /[a-z]+|[A-Z](?:[a-z]+|[A-Z]*(?![a-z]))|[.\d]+/g; -exports.splitName = function (value) { - return String(value).match(splitNameExpression); -}; - -/*** joinName - joins a list of words with a given delimiter - between alphanumeric words. -*/ -exports.joinName = function (delimiter, parts) { - if (exports.no(delimiter)) delimiter = '_'; - parts.unshift([]); - return parts.reduce(function (parts, part) { - if ( - part.match(/\d/) && - exports.len(parts) && parts[parts.length-1].match(/\d/) - ) { - return parts.concat([delimiter + part]); - } else { - return parts.concat([part]); - } - }).join(''); -}; - -/*** upper - converts a name to ``UPPER CASE`` using - a given delimiter between numeric words. - - see: - - `lower` - - `camel` - - `title` - -*/ -exports.upper = function (value, delimiter) { - if (exports.no(delimiter)) - return value.toUpperCase(); - return exports.splitName(value).map(function (part) { - return part.toUpperCase(); - }).join(delimiter); -}; - -/*** lower - converts a name to a ``lower case`` using - a given delimiter between numeric words. - - see: - - `upper` - - `camel` - - `title` - -*/ -exports.lower = function (value, delimiter) { - if (exports.no(delimiter)) - return String(value).toLowerCase(); - return exports.splitName(value).map(function (part) { - return part.toLowerCase(); - }).join(delimiter); -}; - -/*** camel - converts a name to ``camel Case`` using - a given delimiter between numeric words. - - see: - - `lower` - - `upper` - - `title` - -*/ -exports.camel = function (value, delimiter) { - return exports.joinName( - delimiter, - exports.mapApply( - exports.enumerate(exports.splitName(value)), - function (n, part) { - if (n) { - return ( - part.substring(0, 1).toUpperCase() + - part.substring(1).toLowerCase() - ); - } else { - return part.toLowerCase(); - } - } - ) - ); -}; - -/*** title - converts a name to ``Title Case`` using - a given delimiter between numeric words. - - see: - - `lower` - - `upper` - - `camel` - -*/ -exports.title = function (value, delimiter) { - return exports.joinName( - delimiter, - exports.splitName(value).map(function (part) { - return ( - part.substring(0, 1).toUpperCase() + - part.substring(1).toLowerCase() - ); - }) - ); -}; - |