Comparing version 0.2.1 to 0.2.3
159
clone.js
// Generated by CoffeeScript 1.9.1 | ||
(function() { | ||
var clone, merge, typeOf; | ||
var clone, merge, typeOf, | ||
hasProp = {}.hasOwnProperty; | ||
@@ -11,23 +12,34 @@ typeOf = require('./typeOf'); | ||
/* | ||
Clones an object. | ||
Tries to JSON clone it first, then clone.merge it if that fails, while also merging in clone.findRegExp to preserve any RegExp. | ||
Clones an object by iterating over objects and array, re-wrapping them. | ||
Copies over own properties, refrences previous object's __proto__ | ||
*/ | ||
module.exports = clone = function(obj, depth) { | ||
var cloned, err; | ||
module.exports = clone = function(obj, depth, types) { | ||
var skeleton; | ||
if (depth == null) { | ||
depth = clone.depth; | ||
} | ||
try { | ||
cloned = clone.json(obj); | ||
} catch (_error) { | ||
err = _error; | ||
cloned = clone.merge(obj, depth); | ||
if (types == null) { | ||
types = clone.types; | ||
} | ||
return merge(cloned, clone.findRegExp(obj)); | ||
types = clone.castTypes(types); | ||
skeleton = clone.skeleton(obj, null, types); | ||
return clone.iterate(skeleton || {}, obj, depth, types); | ||
}; | ||
clone.json = function(obj) { | ||
return JSON.parse(JSON.stringify(obj)); | ||
clone.skeleton = function(value, type, types) { | ||
if (type == null) { | ||
type = typeOf(value); | ||
} | ||
if (!(type in types)) { | ||
return null; | ||
} | ||
switch (type) { | ||
case 'object': | ||
return {}; | ||
case 'array': | ||
return []; | ||
default: | ||
return null; | ||
} | ||
}; | ||
@@ -37,2 +49,73 @@ | ||
/* | ||
Defaults | ||
*/ | ||
clone.depth = 8; | ||
clone.types = { | ||
object: true, | ||
array: true | ||
}; | ||
clone.castTypes = function(types) { | ||
var i, key, len, obj; | ||
if (typeOf.Object(types)) { | ||
return types; | ||
} | ||
obj = {}; | ||
for (i = 0, len = types.length; i < len; i++) { | ||
key = types[i]; | ||
obj[key] = true; | ||
} | ||
return obj; | ||
}; | ||
clone.iterate = function(obj1, obj2, depth, types) { | ||
var key, parentType, proto, skeleton, type, value; | ||
if (--depth > 0) { | ||
parentType = typeOf(obj2); | ||
for (key in obj2) { | ||
if (!hasProp.call(obj2, key)) continue; | ||
value = obj2[key]; | ||
type = typeOf(value); | ||
if (type in types && (skeleton = clone.skeleton(value, type, types))) { | ||
proto = value.__proto__; | ||
value = clone.iterate(skeleton, value, depth, types); | ||
if (type === 'object' && proto) { | ||
value.__proto__ = clone.iterate({}, proto, depth, types); | ||
} | ||
} | ||
obj1[key] = value; | ||
} | ||
} | ||
return obj1; | ||
}; | ||
/* | ||
[Deprecated.] | ||
*/ | ||
clone.array = function(obj) { | ||
return obj.slice(0); | ||
}; | ||
/* | ||
[Deprecated.] | ||
*/ | ||
clone.json = function(obj, depth) { | ||
var cloned; | ||
if (depth == null) { | ||
depth = clone.depth; | ||
} | ||
cloned = JSON.parse(JSON.stringify(obj)); | ||
return merge(cloned, clone.findRegExp(obj), depth, ['object', 'array']); | ||
}; | ||
/* | ||
[Deprecated.] | ||
Recursively finds all RegExp in an object by creating a deep skeleton object | ||
@@ -51,2 +134,3 @@ containing only the RegExp values. Useful when you wish to preserve RegExp (which can't be done with JSON cloning). | ||
break; | ||
case 'array': | ||
case 'object': | ||
@@ -59,49 +143,2 @@ results[key] = arguments.callee(val); | ||
/* | ||
Deep clones by recursively iterating over each object/array key, building a | ||
new one with each value. | ||
*/ | ||
clone.merge = function(obj, depth) { | ||
var skeleton; | ||
if (depth == null) { | ||
depth = clone.depth; | ||
} | ||
skeleton = typeOf.Array(obj) ? [] : {}; | ||
return clone.merge.iterate(skeleton, obj, depth); | ||
}; | ||
clone.depth = 8; | ||
clone.merge.iterate = function(obj1, obj2, depth) { | ||
var key, obj2Type, wrap; | ||
if (depth == null) { | ||
depth = clone.depth; | ||
} | ||
if (--depth > 0) { | ||
for (key in obj2) { | ||
obj2Type = typeOf(obj2[key]); | ||
wrap = null; | ||
switch (obj2Type) { | ||
case 'object': | ||
wrap = {}; | ||
break; | ||
case 'array': | ||
wrap = []; | ||
} | ||
if (wrap) { | ||
obj1[key] = clone.merge.iterate(wrap, obj2[key], depth); | ||
} else { | ||
obj1[key] = obj2[key]; | ||
} | ||
} | ||
} | ||
return obj1; | ||
}; | ||
clone.array = function(obj) { | ||
return obj.slice(0); | ||
}; | ||
}).call(this); |
@@ -6,42 +6,77 @@ // Generated by CoffeeScript 1.9.1 | ||
module.exports = debounce = function(o, fn) { | ||
var accrued, args, check, execute, hitTime, immediate, lastHitTime, maxWait, reset, that, timer, wait; | ||
var args, cancel, context, immediate, maxWait, result, run, timeout, wait; | ||
timeout = result = context = args = null; | ||
wait = o.wait, maxWait = o.maxWait, immediate = o.immediate; | ||
wait = wait || 0; | ||
maxWait = maxWait || Infinity; | ||
accrued = 0; | ||
timer = hitTime = args = that = lastHitTime = void 0; | ||
execute = function() { | ||
var result; | ||
result = fn.apply(that, args); | ||
accrued = lastHitTime = 0; | ||
reset(); | ||
return result; | ||
run = function() { | ||
result = fn.apply(context, args); | ||
return cancel(); | ||
}; | ||
reset = function() { | ||
return clearTimeout(timer); | ||
cancel = function() { | ||
clearTimeout(timeout); | ||
return timeout = null; | ||
}; | ||
check = function() { | ||
hitTime = new Date(); | ||
if (lastHitTime) { | ||
accrued += hitTime - lastHitTime; | ||
return function() { | ||
args = arguments; | ||
context = this; | ||
if (timeout) { | ||
cancel(); | ||
} else if (immediate) { | ||
lastHitTime = hitTime; | ||
return execute(); | ||
run(); | ||
} | ||
lastHitTime = hitTime; | ||
if (accrued >= maxWait) { | ||
return execute(); | ||
} else { | ||
reset(); | ||
timer = setTimeout(execute, wait); | ||
if (!immediate) { | ||
timeout = setTimeout(run, wait); | ||
} | ||
return null; | ||
return result; | ||
}; | ||
return function() { | ||
args = arguments; | ||
that = this; | ||
return check(); | ||
}; | ||
}; | ||
/* | ||
module.exports = (o, fn) -> | ||
{ wait, maxWait, immediate } = o | ||
* TODO: make immediate work properly | ||
* it currently goes off twice when accruement goes off | ||
* may need to set a "firstTime" variable or something | ||
wait = wait or 0 | ||
maxWait = maxWait or Infinity | ||
accrued = 0 | ||
timer = hitTime = args = that = lastHitTime = undefined | ||
execute = -> | ||
result = fn.apply that, args | ||
accrued = lastHitTime = 0 | ||
reset() | ||
return result | ||
reset = -> clearTimeout timer | ||
check = -> | ||
hitTime = new Date() | ||
if lastHitTime | ||
accrued += hitTime - lastHitTime | ||
else if immediate | ||
lastHitTime = hitTime | ||
return execute() | ||
lastHitTime = hitTime | ||
if accrued >= maxWait | ||
return execute() | ||
else | ||
reset() | ||
timer = setTimeout execute, wait | ||
return null | ||
return -> | ||
args = arguments | ||
that = this | ||
return check() | ||
*/ | ||
}).call(this); |
@@ -6,7 +6,5 @@ // Generated by CoffeeScript 1.9.1 | ||
merge: require('./merge'), | ||
typeOf: require('./typeOf'), | ||
debounce: require('./debounce'), | ||
Transposer: require('transposer') | ||
typeOf: require('./typeOf') | ||
}; | ||
}).call(this); |
70
merge.js
// Generated by CoffeeScript 1.9.1 | ||
(function() { | ||
var merge, typeOf, | ||
hasProp = {}.hasOwnProperty, | ||
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; | ||
hasProp = {}.hasOwnProperty; | ||
@@ -16,14 +15,14 @@ typeOf = require('./typeOf'); | ||
@param depth {Number} | ||
@param iterators {Array} Array of types to iterate over. Defaults to ['object'] | ||
@param types {Array} Array of types to iterate over. Defaults to ['object'] | ||
@return obj1 | ||
*/ | ||
module.exports = merge = function(obj1, obj2, depth, iterators) { | ||
module.exports = merge = function(obj1, obj2, depth, types) { | ||
if (depth == null) { | ||
depth = merge.depth; | ||
} | ||
if (iterators == null) { | ||
iterators = merge.iterators; | ||
if (types == null) { | ||
types = merge.types; | ||
} | ||
return merge.iterate(obj1, obj2, depth, iterators); | ||
return merge.iterate(obj1, obj2, depth, merge.castTypes(types)); | ||
}; | ||
@@ -37,4 +36,4 @@ | ||
merge.white = function(obj1, obj2, depth, iterators) { | ||
return merge.by(obj1, obj2, depth, iterators, true); | ||
merge.white = function(obj1, obj2, depth, types) { | ||
return merge.by(obj1, obj2, depth, types, true); | ||
}; | ||
@@ -48,4 +47,4 @@ | ||
merge.black = function(obj1, obj2, depth, iterators) { | ||
return merge.by(obj1, obj2, depth, iterators, false); | ||
merge.black = function(obj1, obj2, depth, types) { | ||
return merge.by(obj1, obj2, depth, types, false); | ||
}; | ||
@@ -58,7 +57,22 @@ | ||
merge.iterators = ['object']; | ||
merge.depth = 8; | ||
merge.iterate = function(obj1, obj2, depth, iterators) { | ||
merge.types = { | ||
object: true | ||
}; | ||
merge.castTypes = function(types) { | ||
var i, key, len, obj; | ||
if (typeOf.Object(types)) { | ||
return types; | ||
} | ||
obj = {}; | ||
for (i = 0, len = types.length; i < len; i++) { | ||
key = types[i]; | ||
obj[key] = true; | ||
} | ||
return obj; | ||
}; | ||
merge.iterate = function(obj1, obj2, depth, types) { | ||
var key, obj1Type, obj2Type; | ||
@@ -70,4 +84,4 @@ if (depth > 0) { | ||
obj1Type = typeOf(obj1[key]); | ||
if ((indexOf.call(iterators, obj2Type) >= 0) && key in obj1 && (indexOf.call(iterators, obj1Type) >= 0)) { | ||
merge.iterate(obj1[key], obj2[key], depth - 1, iterators); | ||
if ((obj2Type in types) && key in obj1 && (obj1Type in types)) { | ||
merge.iterate(obj1[key], obj2[key], depth - 1, types); | ||
} else { | ||
@@ -81,8 +95,13 @@ obj1[key] = obj2[key]; | ||
merge.by = function(obj1, obj2, depth, iterators, whiteList) { | ||
/* | ||
Merge obj1 and obj2 by replacing values where both objects share the same keys, preffering obj1 | ||
*/ | ||
merge.by = function(obj1, obj2, depth, types, whiteList) { | ||
if (depth == null) { | ||
depth = merge.depth; | ||
} | ||
if (iterators == null) { | ||
iterators = merge.iterators; | ||
if (types == null) { | ||
types = merge.types; | ||
} | ||
@@ -92,6 +111,6 @@ if (whiteList == null) { | ||
} | ||
return merge.by.iterate(obj1, obj2, depth, iterators, whiteList); | ||
return merge.by.iterate(obj1, obj2, depth, merge.castTypes(types), whiteList); | ||
}; | ||
merge.by.iterate = function(obj1, obj2, depth, iterators, whiteList) { | ||
merge.by.iterate = function(obj1, obj2, depth, types, whiteList) { | ||
var key, obj1Type, obj2Type, ref; | ||
@@ -102,10 +121,7 @@ if (depth > 0) { | ||
if (!hasProp.call(ref, key)) continue; | ||
if ((!whiteList && key in obj1) || (whiteList && !(key in obj2))) { | ||
continue; | ||
} | ||
obj2Type = typeOf(obj2[key]); | ||
obj1Type = typeOf(obj1[key]); | ||
if ((indexOf.call(iterators, obj2Type) >= 0) && (indexOf.call(iterators, obj1Type) >= 0)) { | ||
arguments.callee(obj1[key], obj2[key], depth - 1, iterators, whiteList); | ||
} else { | ||
if ((obj2Type in types) && (obj1Type in types)) { | ||
merge.by.iterate(obj1[key], obj2[key], depth - 1, types, whiteList); | ||
} else if (!((!whiteList && key in obj1) || (whiteList && !(key in obj2)))) { | ||
obj1[key] = obj2[key]; | ||
@@ -112,0 +128,0 @@ } |
{ | ||
"name" : "lutils" | ||
, "description" : "A small set of browser-friendly utilities" | ||
, "version" : "0.2.1" | ||
, "version" : "0.2.3" | ||
, "author" : { "name": "nfour" } | ||
@@ -6,0 +6,0 @@ |
# LUtils | ||
A few important utilities which are implimented differently to libraries like `underscore`. Each module is as small as it needs to be, which is ideal for use in the browser. | ||
A few very robust utilities. | ||
- **merge** Merges two objects together | ||
- **merge.white** Merge two objects together, but only properties that exist | ||
- **merge.black** Merge two objects together, but only properties that do not exist | ||
- **typeOf** Consistantly gets the type of a value as a string | ||
- **typeOf[type]** Shortcut function which returns a bool | ||
- **clone** *Reliably* deep clones an object or array, recursively | ||
Include all or be selective. | ||
@@ -15,25 +23,23 @@ ```coffee | ||
## Clone | ||
#### clone( value, ?depth = 8?, ?types = [ 'object', 'array' ]? ) | ||
Clones an object or array as deep as depth. | ||
#### clone( object, depth = 8 ) | ||
Clones an object. | ||
Values which will still remain as references: | ||
- Functions | ||
- Object's `__proto__` (such as `class` instances) | ||
- Any property after `depth` is reached | ||
Tries to JSON clone it first, then clone.merge it if that fails, while also merging in clone.findRegExp to preserve any RegExp. | ||
To clone a function you should explicitly: | ||
```coffee | ||
fn = oldFn.bind() | ||
# or | ||
fn = -> oldFn.apply this, arguments | ||
#### clone.merge( object, depth = 10 ) | ||
Deep clones by recursively iterating over each object/array key, building a new one with each value. | ||
merge fn, oldFn # Merge in any own properties of the function | ||
``` | ||
#### clone.json( object ) | ||
Clones via JSON.stringify then JSON.parse | ||
#### clone.findRegExp( object ) | ||
Recursively finds all RegExp in an object by creating a deep skeleton object containing only the RegExp values. Useful when you wish to preserve RegExp (which can't be done with JSON cloning). | ||
## Merge | ||
#### merge( object1, object2, depth = 8, iterators = [ 'object' ] ) | ||
#### merge( object1, object2, ?depth = 8?, ?types = [ 'object' ]? ) | ||
Merge the second object into the first recursively until depth is reached for each property, replacing object1's values with those in object2. | ||
`iterators` is an array of types that, when matched on a value, will be iterated over and merged in. This means you can merge a function's properties or an array's properties recursively, thus preserving pointer references to the first object's instance. | ||
`types` is an array of types that, when matched on a value, will be iterated over and merged in. This means you can merge a function's properties or an array's properties recursively, thus preserving pointer references to the first object's instance. | ||
@@ -68,10 +74,2 @@ ```coffee | ||
#### merge.iterators = [ 'object' ] | ||
Default iterator types array. | ||
#### merge.depth = 8 | ||
Default depth. | ||
## TypeOf | ||
#### typeOf( value ) | ||
@@ -98,3 +96,3 @@ Returns the primitive type of a value as a lowercase string, very reliable. | ||
### | ||
Avaliable properties (Also in lowercase): | ||
Avaliable properties (Also avaliable in lowercase): | ||
typeOf.Undefined | ||
@@ -111,27 +109,3 @@ typeOf.Boolean | ||
typeOf.NaN | ||
typeOf.Symbol | ||
typeOf.Buffer | ||
### | ||
``` | ||
## Debounce | ||
#### debounce( options, callback ) | ||
```coffee | ||
# Default options | ||
options = { | ||
wait: 0 # Time in ms to accumulate callbacks before finishing | ||
maxWait: Infinity # When reached will call the callback no matter what | ||
immediate: false # Whether to immediately call the callback the first time (Currently broken) | ||
} | ||
options.wait = 1000 | ||
fn = debounce options, -> | ||
console.log 'woo!' | ||
setInterval fn, 100 | ||
# In 10 seconds, 'woo!' will be logged 10 times instead of 100 times | ||
``` |
@@ -11,6 +11,11 @@ // Generated by CoffeeScript 1.9.1 | ||
module.exports = typeOf = function(val) { | ||
return Object.prototype.toString.call(val).slice(8, -1).toLowerCase(); | ||
var type; | ||
type = Object.prototype.toString.call(val).slice(8, -1).toLowerCase(); | ||
if (type === 'number' && isNaN(val)) { | ||
type = 'nan'; | ||
} | ||
return type; | ||
}; | ||
types = ['Undefined', 'Boolean', 'String', 'Function', 'Array', 'Object', 'Null', 'Number', 'Date', 'RegExp', 'NaN', 'Symbol', 'Buffer']; | ||
types = ['Undefined', 'Boolean', 'String', 'Function', 'Array', 'Object', 'Null', 'Number', 'Date', 'RegExp', 'NaN']; | ||
@@ -17,0 +22,0 @@ fn = function(key) { |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
12306
10
329
108
1