Skip to content
Browse files

Simplified caching strategy: If node_modules directory is checked int…

…o source control, rebuild any native deps. Otherwise, restore from the build cache.
  • Loading branch information...
1 parent 347a77b commit ae0756bdbec52315a5221edf0514bb8a7cf0d135 @zeke zeke committed Nov 24, 2013
Showing with 2,790 additions and 176 deletions.
  1. +10 −18 bin/compile
  2. +4 −4 bin/test
  3. 0 test/{shrinkwrap → modules-checked-in}/README.md
  4. +191 −0 test/modules-checked-in/node_modules/hashish/README.markdown
  5. +9 −0 test/modules-checked-in/node_modules/hashish/examples/chain.js
  6. +7 −0 test/modules-checked-in/node_modules/hashish/examples/map.js
  7. +253 −0 test/modules-checked-in/node_modules/hashish/index.js
  8. 0 ...es/euclidean-distance → modules-checked-in/node_modules/hashish/node_modules/traverse}/.npmignore
  9. +3 −0 test/modules-checked-in/node_modules/hashish/node_modules/traverse/.travis.yml
  10. +24 −0 test/modules-checked-in/node_modules/hashish/node_modules/traverse/LICENSE
  11. +16 −0 test/modules-checked-in/node_modules/hashish/node_modules/traverse/examples/json.js
  12. +15 −0 test/modules-checked-in/node_modules/hashish/node_modules/traverse/examples/leaves.js
  13. +8 −0 test/modules-checked-in/node_modules/hashish/node_modules/traverse/examples/negative.js
  14. +10 −0 test/modules-checked-in/node_modules/hashish/node_modules/traverse/examples/scrub.js
  15. +38 −0 test/modules-checked-in/node_modules/hashish/node_modules/traverse/examples/stringify.js
  16. +314 −0 test/modules-checked-in/node_modules/hashish/node_modules/traverse/index.js
  17. +72 −0 test/modules-checked-in/node_modules/hashish/node_modules/traverse/package.json
  18. +209 −0 test/modules-checked-in/node_modules/hashish/node_modules/traverse/readme.markdown
  19. +117 −0 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/circular.js
  20. +37 −0 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/date.js
  21. +240 −0 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/equal.js
  22. +11 −0 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/error.js
  23. +15 −0 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/has.js
  24. +17 −0 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/instance.js
  25. +43 −0 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/interface.js
  26. +49 −0 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/json.js
  27. +31 −0 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/keys.js
  28. +22 −0 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/leaves.js
  29. +96 −0 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/lib/deep_equal.js
  30. +300 −0 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/mutability.js
  31. +21 −0 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/negative.js
  32. +11 −0 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/obj.js
  33. +37 −0 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/siblings.js
  34. +44 −0 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/stop.js
  35. +36 −0 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/stringify.js
  36. +36 −0 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/subexpr.js
  37. +56 −0 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/super_deep.js
  38. +22 −0 test/modules-checked-in/node_modules/hashish/node_modules/traverse/testling/leaves.js
  39. +46 −0 test/modules-checked-in/node_modules/hashish/package.json
  40. +250 −0 test/modules-checked-in/node_modules/hashish/test/hash.js
  41. +69 −0 test/modules-checked-in/node_modules/hashish/test/property.js
  42. +1 −1 test/{shrinkwrap → modules-checked-in}/package.json
  43. +0 −38 test/shrinkwrap/node_modules/euclidean-distance/README.md
  44. +0 −23 test/shrinkwrap/node_modules/euclidean-distance/index.js
  45. +0 −39 test/shrinkwrap/node_modules/euclidean-distance/package.json
  46. +0 −41 test/shrinkwrap/node_modules/euclidean-distance/test/indexTest.js
  47. +0 −2 test/shrinkwrap/node_modules/euclidean-distance/test/mocha.opts
  48. +0 −10 test/shrinkwrap/npm-shrinkwrap.json
View
28 bin/compile
@@ -6,7 +6,7 @@ set -o pipefail # don't ignore exit codes when piping output
# Configure directories
build_dir=$1
-cache_basedir=$2
+cache_dir=$2
bp_dir=$(cd $(dirname $0); cd ..; pwd)
# Load some convenience functions like status(), echo(), and indent()
@@ -54,23 +54,15 @@ PATH=$PATH:$build_dir/vendor/node/bin
# Run subsequent node/npm commands from the build path
cd $build_dir
-if test -f $build_dir/npm-shrinkwrap.json; then
- # Use npm-shrinkwrap.json's checksum as the cachebuster
- status "Found npm-shrinkwrap.json"
- shrinkwrap_checksum=$(cat $build_dir/npm-shrinkwrap.json | md5sum | awk '{print $1}')
- cache_dir="$cache_basedir/$shrinkwrap_checksum"
- test -d $cache_dir && status "npm-shrinkwrap.json unchanged since last build"
-else
- # Fall back to package.json as the cachebuster.
- protip "Use npm shrinkwrap to lock down dependency versions"
- package_json_checksum=$(cat $build_dir/package.json | md5sum | awk '{print $1}')
- cache_dir="$cache_basedir/$package_json_checksum"
- test -d $cache_dir && status "package.json unchanged since last build"
-fi
-
-if test -d $cache_dir; then
+# If node_modules directory is checked into source control then
+# rebuild any native deps. Otherwise, restore from the build cache.
+if test -d $build_dir/node_modules; then
+ status "Using existing node_modules directory"
+ status "Rebuilding any native dependencies"
+ npm rebuild 2>&1 | indent
+elif test -d $cache_dir/node_modules; then
status "Restoring node_modules from cache"
- test -d $cache_dir/node_modules && cp -r $cache_dir/node_modules $build_dir/
+ cp -r $cache_dir/node_modules $build_dir/
fi
# Make npm output to STDOUT instead of its default STDERR
@@ -80,7 +72,7 @@ npm install --production 2>&1 | indent
status "Pruning unused dependencies"
npm prune 2>&1 | indent
-status "Caching node_modules for future builds"
+status "Caching node_modules directory for future builds"
rm -rf $cache_dir
mkdir -p $cache_dir
test -d $build_dir/node_modules && cp -r $build_dir/node_modules $cache_dir/
View
8 bin/test
@@ -70,10 +70,10 @@ testNodeModulesCached() {
assertEquals "1" "$(ls -1 $cache/ | wc -l)"
}
-testShrinkwrap() {
- compile "shrinkwrap"
- assertCaptured "Found npm-shrinkwrap.json"
- assertNotCaptured "PRO TIP: Use npm shrinkwrap"
+testModulesCheckedIn() {
+ compile "modules-checked-in"
+ assertCaptured "Using existing node_modules directory"
+ assertCaptured "Rebuilding any native dependencies"
assertCapturedSuccess
}
View
0 test/shrinkwrap/README.md → test/modules-checked-in/README.md
File renamed without changes.
View
191 test/modules-checked-in/node_modules/hashish/README.markdown
@@ -0,0 +1,191 @@
+Hashish
+=======
+
+Hashish is a node.js library for manipulating hash data structures.
+It is distilled from the finest that ruby, perl, and haskell have to offer by
+way of hash/map interfaces.
+
+Hashish provides a chaining interface, where you can do:
+
+ var Hash = require('hashish');
+
+ Hash({ a : 1, b : 2, c : 3, d : 4 })
+ .map(function (x) { return x * 10 })
+ .filter(function (x) { return x < 30 })
+ .forEach(function (x, key) {
+ console.log(key + ' => ' + x);
+ })
+ ;
+
+Output:
+
+ a => 10
+ b => 20
+
+Some functions and attributes in the chaining interface are terminal, like
+`.items` or `.detect()`. They return values of their own instead of the chain
+context.
+
+Each function in the chainable interface is also attached to `Hash` in chainless
+form:
+
+ var Hash = require('hashish');
+ var obj = { a : 1, b : 2, c : 3, d : 4 };
+
+ var mapped = Hash.map(obj, function (x) {
+ return x * 10
+ });
+
+ console.dir(mapped);
+
+Output:
+
+ { a: 10, b: 20, c: 30, d: 40 }
+
+In either case, the 'this' context of the function calls is the same object that
+the chained functions return, so you can make nested chains.
+
+Methods
+=======
+
+forEach(cb)
+-----------
+
+For each key/value in the hash, calls `cb(value, key)`.
+
+map(cb)
+-------
+
+For each key/value in the hash, calls `cb(value, key)`.
+The return value of `cb` is the new value at `key` in the resulting hash.
+
+filter(cb)
+----------
+
+For each key/value in the hash, calls `cb(value, key)`.
+The resulting hash omits key/value pairs where `cb` returned a falsy value.
+
+detect(cb)
+----------
+
+Returns the first value in the hash for which `cb(value, key)` is non-falsy.
+Order of hashes is not well-defined so watch out for that.
+
+reduce(cb)
+----------
+
+Returns the accumulated value of a left-fold over the key/value pairs.
+
+some(cb)
+--------
+
+Returns a boolean: whether or not `cb(value, key)` ever returned a non-falsy
+value.
+
+update(obj1, [obj2, obj3, ...])
+-----------
+
+Mutate the context hash, merging the key/value pairs from the passed objects
+and overwriting keys from the context hash if the current `obj` has keys of
+the same name. Falsy arguments are silently ignored.
+
+updateAll([ obj1, obj2, ... ])
+------------------------------
+
+Like multi-argument `update()` but operate on an array directly.
+
+merge(obj1, [obj2, obj3, ...])
+----------
+
+Merge the key/value pairs from the passed objects into the resultant hash
+without modifying the context hash. Falsy arguments are silently ignored.
+
+mergeAll([ obj1, obj2, ... ])
+------------------------------
+
+Like multi-argument `merge()` but operate on an array directly.
+
+has(key)
+--------
+
+Return whether the hash has a key, `key`.
+
+valuesAt(keys)
+--------------
+
+Return an Array with the values at the keys from `keys`.
+
+tap(cb)
+-------
+
+Call `cb` with the present raw hash.
+This function is chainable.
+
+extract(keys)
+-------------
+
+Filter by including only those keys in `keys` in the resulting hash.
+
+exclude(keys)
+-------------
+
+Filter by excluding those keys in `keys` in the resulting hash.
+
+Attributes
+==========
+
+These are attributes in the chaining interface and functions in the `Hash.xxx`
+interface.
+
+keys
+----
+
+Return all the enumerable attribute keys in the hash.
+
+values
+------
+
+Return all the enumerable attribute values in the hash.
+
+compact
+-------
+
+Filter out values which are `=== undefined`.
+
+clone
+-----
+
+Make a deep copy of the hash.
+
+copy
+----
+
+Make a shallow copy of the hash.
+
+length
+------
+
+Return the number of key/value pairs in the hash.
+Note: use `Hash.size()` for non-chain mode.
+
+size
+----
+
+Alias for `length` since `Hash.length` is masked by `Function.prototype`.
+
+See Also
+========
+
+See also [creationix's pattern/hash](http://github.com/creationix/pattern),
+which does a similar thing except with hash inputs and array outputs.
+
+Installation
+============
+
+To install with [npm](http://github.com/isaacs/npm):
+
+ npm install hashish
+
+To run the tests with [expresso](http://github.com/visionmedia/expresso):
+
+ expresso
View
9 test/modules-checked-in/node_modules/hashish/examples/chain.js
@@ -0,0 +1,9 @@
+var Hash = require('hashish');
+
+Hash({ a : 1, b : 2, c : 3, d : 4 })
+ .map(function (x) { return x * 10 })
+ .filter(function (x) { return x < 30 })
+ .forEach(function (x, key) {
+ console.log(key + ' => ' + x);
+ })
+;
View
7 test/modules-checked-in/node_modules/hashish/examples/map.js
@@ -0,0 +1,7 @@
+var Hash = require('hashish');
+var obj = { a : 1, b : 2, c : 3, d : 4 };
+
+var mapped = Hash.map(obj, function (x) {
+ return x * 10
+});
+console.dir(mapped);
View
253 test/modules-checked-in/node_modules/hashish/index.js
@@ -0,0 +1,253 @@
+module.exports = Hash;
+var Traverse = require('traverse');
+
+function Hash (hash, xs) {
+ if (Array.isArray(hash) && Array.isArray(xs)) {
+ var to = Math.min(hash.length, xs.length);
+ var acc = {};
+ for (var i = 0; i < to; i++) {
+ acc[hash[i]] = xs[i];
+ }
+ return Hash(acc);
+ }
+
+ if (hash === undefined) return Hash({});
+
+ var self = {
+ map : function (f) {
+ var acc = { __proto__ : hash.__proto__ };
+ Object.keys(hash).forEach(function (key) {
+ acc[key] = f.call(self, hash[key], key);
+ });
+ return Hash(acc);
+ },
+ forEach : function (f) {
+ Object.keys(hash).forEach(function (key) {
+ f.call(self, hash[key], key);
+ });
+ return self;
+ },
+ filter : function (f) {
+ var acc = { __proto__ : hash.__proto__ };
+ Object.keys(hash).forEach(function (key) {
+ if (f.call(self, hash[key], key)) {
+ acc[key] = hash[key];
+ }
+ });
+ return Hash(acc);
+ },
+ detect : function (f) {
+ for (var key in hash) {
+ if (f.call(self, hash[key], key)) {
+ return hash[key];
+ }
+ }
+ return undefined;
+ },
+ reduce : function (f, acc) {
+ var keys = Object.keys(hash);
+ if (acc === undefined) acc = keys.shift();
+ keys.forEach(function (key) {
+ acc = f.call(self, acc, hash[key], key);
+ });
+ return acc;
+ },
+ some : function (f) {
+ for (var key in hash) {
+ if (f.call(self, hash[key], key)) return true;
+ }
+ return false;
+ },
+ update : function (obj) {
+ if (arguments.length > 1) {
+ self.updateAll([].slice.call(arguments));
+ }
+ else {
+ Object.keys(obj).forEach(function (key) {
+ hash[key] = obj[key];
+ });
+ }
+ return self;
+ },
+ updateAll : function (xs) {
+ xs.filter(Boolean).forEach(function (x) {
+ self.update(x);
+ });
+ return self;
+ },
+ merge : function (obj) {
+ if (arguments.length > 1) {
+ return self.copy.updateAll([].slice.call(arguments));
+ }
+ else {
+ return self.copy.update(obj);
+ }
+ },
+ mergeAll : function (xs) {
+ return self.copy.updateAll(xs);
+ },
+ has : function (key) { // only operates on enumerables
+ return Array.isArray(key)
+ ? key.every(function (k) { return self.has(k) })
+ : self.keys.indexOf(key.toString()) >= 0;
+ },
+ valuesAt : function (keys) {
+ return Array.isArray(keys)
+ ? keys.map(function (key) { return hash[key] })
+ : hash[keys]
+ ;
+ },
+ tap : function (f) {
+ f.call(self, hash);
+ return self;
+ },
+ extract : function (keys) {
+ var acc = {};
+ keys.forEach(function (key) {
+ acc[key] = hash[key];
+ });
+ return Hash(acc);
+ },
+ exclude : function (keys) {
+ return self.filter(function (_, key) {
+ return keys.indexOf(key) < 0
+ });
+ },
+ end : hash,
+ items : hash
+ };
+
+ var props = {
+ keys : function () { return Object.keys(hash) },
+ values : function () {
+ return Object.keys(hash).map(function (key) { return hash[key] });
+ },
+ compact : function () {
+ return self.filter(function (x) { return x !== undefined });
+ },
+ clone : function () { return Hash(Hash.clone(hash)) },
+ copy : function () { return Hash(Hash.copy(hash)) },
+ length : function () { return Object.keys(hash).length },
+ size : function () { return self.length }
+ };
+
+ if (Object.defineProperty) {
+ // es5-shim has an Object.defineProperty but it throws for getters
+ try {
+ for (var key in props) {
+ Object.defineProperty(self, key, { get : props[key] });
+ }
+ }
+ catch (err) {
+ for (var key in props) {
+ if (key !== 'clone' && key !== 'copy' && key !== 'compact') {
+ // ^ those keys use Hash() so can't call them without
+ // a stack overflow
+ self[key] = props[key]();
+ }
+ }
+ }
+ }
+ else if (self.__defineGetter__) {
+ for (var key in props) {
+ self.__defineGetter__(key, props[key]);
+ }
+ }
+ else {
+ // non-lazy version for browsers that suck >_<
+ for (var key in props) {
+ self[key] = props[key]();
+ }
+ }
+
+ return self;
+};
+
+// deep copy
+Hash.clone = function (ref) {
+ return Traverse.clone(ref);
+};
+
+// shallow copy
+Hash.copy = function (ref) {
+ var hash = { __proto__ : ref.__proto__ };
+ Object.keys(ref).forEach(function (key) {
+ hash[key] = ref[key];
+ });
+ return hash;
+};
+
+Hash.map = function (ref, f) {
+ return Hash(ref).map(f).items;
+};
+
+Hash.forEach = function (ref, f) {
+ Hash(ref).forEach(f);
+};
+
+Hash.filter = function (ref, f) {
+ return Hash(ref).filter(f).items;
+};
+
+Hash.detect = function (ref, f) {
+ return Hash(ref).detect(f);
+};
+
+Hash.reduce = function (ref, f, acc) {
+ return Hash(ref).reduce(f, acc);
+};
+
+Hash.some = function (ref, f) {
+ return Hash(ref).some(f);
+};
+
+Hash.update = function (a /*, b, c, ... */) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ var hash = Hash(a);
+ return hash.update.apply(hash, args).items;
+};
+
+Hash.merge = function (a /*, b, c, ... */) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ var hash = Hash(a);
+ return hash.merge.apply(hash, args).items;
+};
+
+Hash.has = function (ref, key) {
+ return Hash(ref).has(key);
+};
+
+Hash.valuesAt = function (ref, keys) {
+ return Hash(ref).valuesAt(keys);
+};
+
+Hash.tap = function (ref, f) {
+ return Hash(ref).tap(f).items;
+};
+
+Hash.extract = function (ref, keys) {
+ return Hash(ref).extract(keys).items;
+};
+
+Hash.exclude = function (ref, keys) {
+ return Hash(ref).exclude(keys).items;
+};
+
+Hash.concat = function (xs) {
+ var hash = Hash({});
+ xs.forEach(function (x) { hash.update(x) });
+ return hash.items;
+};
+
+Hash.zip = function (xs, ys) {
+ return Hash(xs, ys).items;
+};
+
+// .length is already defined for function prototypes
+Hash.size = function (ref) {
+ return Hash(ref).size;
+};
+
+Hash.compact = function (ref) {
+ return Hash(ref).compact.items;
+};
View
0 ...ode_modules/euclidean-distance/.npmignore → .../hashish/node_modules/traverse/.npmignore
File renamed without changes.
View
3 test/modules-checked-in/node_modules/hashish/node_modules/traverse/.travis.yml
@@ -0,0 +1,3 @@
+language: node_js
+node_js:
+ - 0.6
View
24 test/modules-checked-in/node_modules/hashish/node_modules/traverse/LICENSE
@@ -0,0 +1,24 @@
+Copyright 2010 James Halliday (mail@substack.net)
+
+This project is free software released under the MIT/X11 license:
+http://www.opensource.org/licenses/mit-license.php
+
+Copyright 2010 James Halliday (mail@substack.net)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
View
16 test/modules-checked-in/node_modules/hashish/node_modules/traverse/examples/json.js
@@ -0,0 +1,16 @@
+var traverse = require('traverse');
+
+var id = 54;
+var callbacks = {};
+var obj = { moo : function () {}, foo : [2,3,4, function () {}] };
+
+var scrubbed = traverse(obj).map(function (x) {
+ if (typeof x === 'function') {
+ callbacks[id] = { id : id, f : x, path : this.path };
+ this.update('[Function]');
+ id++;
+ }
+});
+
+console.dir(scrubbed);
+console.dir(callbacks);
View
15 test/modules-checked-in/node_modules/hashish/node_modules/traverse/examples/leaves.js
@@ -0,0 +1,15 @@
+var traverse = require('traverse');
+
+var obj = {
+ a : [1,2,3],
+ b : 4,
+ c : [5,6],
+ d : { e : [7,8], f : 9 },
+};
+
+var leaves = traverse(obj).reduce(function (acc, x) {
+ if (this.isLeaf) acc.push(x);
+ return acc;
+}, []);
+
+console.dir(leaves);
View
8 test/modules-checked-in/node_modules/hashish/node_modules/traverse/examples/negative.js
@@ -0,0 +1,8 @@
+var traverse = require('traverse');
+var obj = [ 5, 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ];
+
+traverse(obj).forEach(function (x) {
+ if (x < 0) this.update(x + 128);
+});
+
+console.dir(obj);
View
10 test/modules-checked-in/node_modules/hashish/node_modules/traverse/examples/scrub.js
@@ -0,0 +1,10 @@
+// scrub out circular references
+var traverse = require('traverse');
+
+var obj = { a : 1, b : 2, c : [ 3, 4 ] };
+obj.c.push(obj);
+
+var scrubbed = traverse(obj).map(function (x) {
+ if (this.circular) this.remove()
+});
+console.dir(scrubbed);
View
38 test/modules-checked-in/node_modules/hashish/node_modules/traverse/examples/stringify.js
@@ -0,0 +1,38 @@
+#!/usr/bin/env node
+var traverse = require('traverse');
+
+var obj = [ 'five', 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ];
+
+var s = '';
+traverse(obj).forEach(function to_s (node) {
+ if (Array.isArray(node)) {
+ this.before(function () { s += '[' });
+ this.post(function (child) {
+ if (!child.isLast) s += ',';
+ });
+ this.after(function () { s += ']' });
+ }
+ else if (typeof node == 'object') {
+ this.before(function () { s += '{' });
+ this.pre(function (x, key) {
+ to_s(key);
+ s += ':';
+ });
+ this.post(function (child) {
+ if (!child.isLast) s += ',';
+ });
+ this.after(function () { s += '}' });
+ }
+ else if (typeof node == 'string') {
+ s += '"' + node.toString().replace(/"/g, '\\"') + '"';
+ }
+ else if (typeof node == 'function') {
+ s += 'null';
+ }
+ else {
+ s += node.toString();
+ }
+});
+
+console.log('JSON.stringify: ' + JSON.stringify(obj));
+console.log('this stringify: ' + s);
View
314 test/modules-checked-in/node_modules/hashish/node_modules/traverse/index.js
@@ -0,0 +1,314 @@
+var traverse = module.exports = function (obj) {
+ return new Traverse(obj);
+};
+
+function Traverse (obj) {
+ this.value = obj;
+}
+
+Traverse.prototype.get = function (ps) {
+ var node = this.value;
+ for (var i = 0; i < ps.length; i ++) {
+ var key = ps[i];
+ if (!node || !hasOwnProperty.call(node, key)) {
+ node = undefined;
+ break;
+ }
+ node = node[key];
+ }
+ return node;
+};
+
+Traverse.prototype.has = function (ps) {
+ var node = this.value;
+ for (var i = 0; i < ps.length; i ++) {
+ var key = ps[i];
+ if (!node || !hasOwnProperty.call(node, key)) {
+ return false;
+ }
+ node = node[key];
+ }
+ return true;
+};
+
+Traverse.prototype.set = function (ps, value) {
+ var node = this.value;
+ for (var i = 0; i < ps.length - 1; i ++) {
+ var key = ps[i];
+ if (!hasOwnProperty.call(node, key)) node[key] = {};
+ node = node[key];
+ }
+ node[ps[i]] = value;
+ return value;
+};
+
+Traverse.prototype.map = function (cb) {
+ return walk(this.value, cb, true);
+};
+
+Traverse.prototype.forEach = function (cb) {
+ this.value = walk(this.value, cb, false);
+ return this.value;
+};
+
+Traverse.prototype.reduce = function (cb, init) {
+ var skip = arguments.length === 1;
+ var acc = skip ? this.value : init;
+ this.forEach(function (x) {
+ if (!this.isRoot || !skip) {
+ acc = cb.call(this, acc, x);
+ }
+ });
+ return acc;
+};
+
+Traverse.prototype.paths = function () {
+ var acc = [];
+ this.forEach(function (x) {
+ acc.push(this.path);
+ });
+ return acc;
+};
+
+Traverse.prototype.nodes = function () {
+ var acc = [];
+ this.forEach(function (x) {
+ acc.push(this.node);
+ });
+ return acc;
+};
+
+Traverse.prototype.clone = function () {
+ var parents = [], nodes = [];
+
+ return (function clone (src) {
+ for (var i = 0; i < parents.length; i++) {
+ if (parents[i] === src) {
+ return nodes[i];
+ }
+ }
+
+ if (typeof src === 'object' && src !== null) {
+ var dst = copy(src);
+
+ parents.push(src);
+ nodes.push(dst);
+
+ forEach(objectKeys(src), function (key) {
+ dst[key] = clone(src[key]);
+ });
+
+ parents.pop();
+ nodes.pop();
+ return dst;
+ }
+ else {
+ return src;
+ }
+ })(this.value);
+};
+
+function walk (root, cb, immutable) {
+ var path = [];
+ var parents = [];
+ var alive = true;
+
+ return (function walker (node_) {
+ var node = immutable ? copy(node_) : node_;
+ var modifiers = {};
+
+ var keepGoing = true;
+
+ var state = {
+ node : node,
+ node_ : node_,
+ path : [].concat(path),
+ parent : parents[parents.length - 1],
+ parents : parents,
+ key : path.slice(-1)[0],
+ isRoot : path.length === 0,
+ level : path.length,
+ circular : null,
+ update : function (x, stopHere) {
+ if (!state.isRoot) {
+ state.parent.node[state.key] = x;
+ }
+ state.node = x;
+ if (stopHere) keepGoing = false;
+ },
+ 'delete' : function (stopHere) {
+ delete state.parent.node[state.key];
+ if (stopHere) keepGoing = false;
+ },
+ remove : function (stopHere) {
+ if (isArray(state.parent.node)) {
+ state.parent.node.splice(state.key, 1);
+ }
+ else {
+ delete state.parent.node[state.key];
+ }
+ if (stopHere) keepGoing = false;
+ },
+ keys : null,
+ before : function (f) { modifiers.before = f },
+ after : function (f) { modifiers.after = f },
+ pre : function (f) { modifiers.pre = f },
+ post : function (f) { modifiers.post = f },
+ stop : function () { alive = false },
+ block : function () { keepGoing = false }
+ };
+
+ if (!alive) return state;
+
+ function updateState() {
+ if (typeof state.node === 'object' && state.node !== null) {
+ if (!state.keys || state.node_ !== state.node) {
+ state.keys = objectKeys(state.node)
+ }
+
+ state.isLeaf = state.keys.length == 0;
+
+ for (var i = 0; i < parents.length; i++) {
+ if (parents[i].node_ === node_) {
+ state.circular = parents[i];
+ break;
+ }
+ }
+ }
+ else {
+ state.isLeaf = true;
+ state.keys = null;
+ }
+
+ state.notLeaf = !state.isLeaf;
+ state.notRoot = !state.isRoot;
+ }
+
+ updateState();
+
+ // use return values to update if defined
+ var ret = cb.call(state, state.node);
+ if (ret !== undefined && state.update) state.update(ret);
+
+ if (modifiers.before) modifiers.before.call(state, state.node);
+
+ if (!keepGoing) return state;
+
+ if (typeof state.node == 'object'
+ && state.node !== null && !state.circular) {
+ parents.push(state);
+
+ updateState();
+
+ forEach(state.keys, function (key, i) {
+ path.push(key);
+
+ if (modifiers.pre) modifiers.pre.call(state, state.node[key], key);
+
+ var child = walker(state.node[key]);
+ if (immutable && hasOwnProperty.call(state.node, key)) {
+ state.node[key] = child.node;
+ }
+
+ child.isLast = i == state.keys.length - 1;
+ child.isFirst = i == 0;
+
+ if (modifiers.post) modifiers.post.call(state, child);
+
+ path.pop();
+ });
+ parents.pop();
+ }
+
+ if (modifiers.after) modifiers.after.call(state, state.node);
+
+ return state;
+ })(root).node;
+}
+
+function copy (src) {
+ if (typeof src === 'object' && src !== null) {
+ var dst;
+
+ if (isArray(src)) {
+ dst = [];
+ }
+ else if (isDate(src)) {
+ dst = new Date(src.getTime ? src.getTime() : src);
+ }
+ else if (isRegExp(src)) {
+ dst = new RegExp(src);
+ }
+ else if (isError(src)) {
+ dst = { message: src.message };
+ }
+ else if (isBoolean(src)) {
+ dst = new Boolean(src);
+ }
+ else if (isNumber(src)) {
+ dst = new Number(src);
+ }
+ else if (isString(src)) {
+ dst = new String(src);
+ }
+ else if (Object.create && Object.getPrototypeOf) {
+ dst = Object.create(Object.getPrototypeOf(src));
+ }
+ else if (src.constructor === Object) {
+ dst = {};
+ }
+ else {
+ var proto =
+ (src.constructor && src.constructor.prototype)
+ || src.__proto__
+ || {}
+ ;
+ var T = function () {};
+ T.prototype = proto;
+ dst = new T;
+ }
+
+ forEach(objectKeys(src), function (key) {
+ dst[key] = src[key];
+ });
+ return dst;
+ }
+ else return src;
+}
+
+var objectKeys = Object.keys || function keys (obj) {
+ var res = [];
+ for (var key in obj) res.push(key)
+ return res;
+};
+
+function toS (obj) { return Object.prototype.toString.call(obj) }
+function isDate (obj) { return toS(obj) === '[object Date]' }
+function isRegExp (obj) { return toS(obj) === '[object RegExp]' }
+function isError (obj) { return toS(obj) === '[object Error]' }
+function isBoolean (obj) { return toS(obj) === '[object Boolean]' }
+function isNumber (obj) { return toS(obj) === '[object Number]' }
+function isString (obj) { return toS(obj) === '[object String]' }
+
+var isArray = Array.isArray || function isArray (xs) {
+ return Object.prototype.toString.call(xs) === '[object Array]';
+};
+
+var forEach = function (xs, fn) {
+ if (xs.forEach) return xs.forEach(fn)
+ else for (var i = 0; i < xs.length; i++) {
+ fn(xs[i], i, xs);
+ }
+};
+
+forEach(objectKeys(Traverse.prototype), function (key) {
+ traverse[key] = function (obj) {
+ var args = [].slice.call(arguments, 1);
+ var t = new Traverse(obj);
+ return t[key].apply(t, args);
+ };
+});
+
+var hasOwnProperty = Object.hasOwnProperty || function (obj, key) {
+ return key in obj;
+};
View
72 test/modules-checked-in/node_modules/hashish/node_modules/traverse/package.json
@@ -0,0 +1,72 @@
+{
+ "name": "traverse",
+ "version": "0.6.6",
+ "description": "traverse and transform objects by visiting every node on a recursive walk",
+ "main": "index.js",
+ "directories": {
+ "example": "example",
+ "test": "test"
+ },
+ "devDependencies": {
+ "tape": "~1.0.4"
+ },
+ "scripts": {
+ "test": "tape test/*.js"
+ },
+ "testling": {
+ "files": "test/*.js",
+ "browsers": {
+ "iexplore": [
+ "6.0",
+ "7.0",
+ "8.0",
+ "9.0"
+ ],
+ "chrome": [
+ "10.0",
+ "20.0"
+ ],
+ "firefox": [
+ "10.0",
+ "15.0"
+ ],
+ "safari": [
+ "5.1"
+ ],
+ "opera": [
+ "12.0"
+ ]
+ }
+ },
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/substack/js-traverse.git"
+ },
+ "homepage": "https://github.com/substack/js-traverse",
+ "keywords": [
+ "traverse",
+ "walk",
+ "recursive",
+ "map",
+ "forEach",
+ "deep",
+ "clone"
+ ],
+ "author": {
+ "name": "James Halliday",
+ "email": "mail@substack.net",
+ "url": "http://substack.net"
+ },
+ "license": "MIT",
+ "readme": "# traverse\n\nTraverse and transform objects by visiting every node on a recursive walk.\n\n[![browser support](http://ci.testling.com/substack/js-traverse.png)](http://ci.testling.com/substack/js-traverse)\n\n[![build status](https://secure.travis-ci.org/substack/js-traverse.png)](http://travis-ci.org/substack/js-traverse)\n\n# examples\n\n## transform negative numbers in-place\n\nnegative.js\n\n````javascript\nvar traverse = require('traverse');\nvar obj = [ 5, 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ];\n\ntraverse(obj).forEach(function (x) {\n if (x < 0) this.update(x + 128);\n});\n\nconsole.dir(obj);\n````\n\nOutput:\n\n [ 5, 6, 125, [ 7, 8, 126, 1 ], { f: 10, g: 115 } ]\n\n## collect leaf nodes\n\nleaves.js\n\n````javascript\nvar traverse = require('traverse');\n\nvar obj = {\n a : [1,2,3],\n b : 4,\n c : [5,6],\n d : { e : [7,8], f : 9 },\n};\n\nvar leaves = traverse(obj).reduce(function (acc, x) {\n if (this.isLeaf) acc.push(x);\n return acc;\n}, []);\n\nconsole.dir(leaves);\n````\n\nOutput:\n\n [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]\n\n## scrub circular references\n\nscrub.js:\n\n````javascript\nvar traverse = require('traverse');\n\nvar obj = { a : 1, b : 2, c : [ 3, 4 ] };\nobj.c.push(obj);\n\nvar scrubbed = traverse(obj).map(function (x) {\n if (this.circular) this.remove()\n});\nconsole.dir(scrubbed);\n````\n\noutput:\n\n { a: 1, b: 2, c: [ 3, 4 ] }\n\n# methods\n\nEach method that takes an `fn` uses the context documented below in the context\nsection.\n\n## .map(fn)\n\nExecute `fn` for each node in the object and return a new object with the\nresults of the walk. To update nodes in the result use `this.update(value)`.\n\n## .forEach(fn)\n\nExecute `fn` for each node in the object but unlike `.map()`, when\n`this.update()` is called it updates the object in-place.\n\n## .reduce(fn, acc)\n\nFor each node in the object, perform a\n[left-fold](http://en.wikipedia.org/wiki/Fold_(higher-order_function))\nwith the return value of `fn(acc, node)`.\n\nIf `acc` isn't specified, `acc` is set to the root object for the first step\nand the root element is skipped.\n\n## .paths()\n\nReturn an `Array` of every possible non-cyclic path in the object.\nPaths are `Array`s of string keys.\n\n## .nodes()\n\nReturn an `Array` of every node in the object.\n\n## .clone()\n\nCreate a deep clone of the object.\n\n## .get(path)\n\nGet the element at the array `path`.\n\n## .set(path, value)\n\nSet the element at the array `path` to `value`.\n\n## .has(path)\n\nReturn whether the element at the array `path` exists.\n\n# context\n\nEach method that takes a callback has a context (its `this` object) with these\nattributes:\n\n## this.node\n\nThe present node on the recursive walk\n\n## this.path\n\nAn array of string keys from the root to the present node\n\n## this.parent\n\nThe context of the node's parent.\nThis is `undefined` for the root node.\n\n## this.key\n\nThe name of the key of the present node in its parent.\nThis is `undefined` for the root node.\n\n## this.isRoot, this.notRoot\n\nWhether the present node is the root node\n\n## this.isLeaf, this.notLeaf\n\nWhether or not the present node is a leaf node (has no children)\n\n## this.level\n\nDepth of the node within the traversal\n\n## this.circular\n\nIf the node equals one of its parents, the `circular` attribute is set to the\ncontext of that parent and the traversal progresses no deeper.\n\n## this.update(value, stopHere=false)\n\nSet a new value for the present node.\n\nAll the elements in `value` will be recursively traversed unless `stopHere` is\ntrue.\n\n## this.remove(stopHere=false)\n\nRemove the current element from the output. If the node is in an Array it will\nbe spliced off. Otherwise it will be deleted from its parent.\n\n## this.delete(stopHere=false)\n\nDelete the current element from its parent in the output. Calls `delete` even on\nArrays.\n\n## this.before(fn)\n\nCall this function before any of the children are traversed.\n\nYou can assign into `this.keys` here to traverse in a custom order.\n\n## this.after(fn)\n\nCall this function after any of the children are traversed.\n\n## this.pre(fn)\n\nCall this function before each of the children are traversed.\n\n## this.post(fn)\n\nCall this function after each of the children are traversed.\n\n\n# install\n\nUsing [npm](http://npmjs.org) do:\n\n $ npm install traverse\n\n# license\n\nMIT\n",
+ "readmeFilename": "readme.markdown",
+ "bugs": {
+ "url": "https://github.com/substack/js-traverse/issues"
+ },
+ "_id": "traverse@0.6.6",
+ "dist": {
+ "shasum": "887acce42e0d9aa00e0e7e4c00c29529d7df90f2"
+ },
+ "_from": "traverse@>=0.2.4",
+ "_resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz"
+}
View
209 test/modules-checked-in/node_modules/hashish/node_modules/traverse/readme.markdown
@@ -0,0 +1,209 @@
+# traverse
+
+Traverse and transform objects by visiting every node on a recursive walk.
+
+[![browser support](http://ci.testling.com/substack/js-traverse.png)](http://ci.testling.com/substack/js-traverse)
+
+[![build status](https://secure.travis-ci.org/substack/js-traverse.png)](http://travis-ci.org/substack/js-traverse)
+
+# examples
+
+## transform negative numbers in-place
+
+negative.js
+
+````javascript
+var traverse = require('traverse');
+var obj = [ 5, 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ];
+
+traverse(obj).forEach(function (x) {
+ if (x < 0) this.update(x + 128);
+});
+
+console.dir(obj);
+````
+
+Output:
+
+ [ 5, 6, 125, [ 7, 8, 126, 1 ], { f: 10, g: 115 } ]
+
+## collect leaf nodes
+
+leaves.js
+
+````javascript
+var traverse = require('traverse');
+
+var obj = {
+ a : [1,2,3],
+ b : 4,
+ c : [5,6],
+ d : { e : [7,8], f : 9 },
+};
+
+var leaves = traverse(obj).reduce(function (acc, x) {
+ if (this.isLeaf) acc.push(x);
+ return acc;
+}, []);
+
+console.dir(leaves);
+````
+
+Output:
+
+ [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
+
+## scrub circular references
+
+scrub.js:
+
+````javascript
+var traverse = require('traverse');
+
+var obj = { a : 1, b : 2, c : [ 3, 4 ] };
+obj.c.push(obj);
+
+var scrubbed = traverse(obj).map(function (x) {
+ if (this.circular) this.remove()
+});
+console.dir(scrubbed);
+````
+
+output:
+
+ { a: 1, b: 2, c: [ 3, 4 ] }
+
+# methods
+
+Each method that takes an `fn` uses the context documented below in the context
+section.
+
+## .map(fn)
+
+Execute `fn` for each node in the object and return a new object with the
+results of the walk. To update nodes in the result use `this.update(value)`.
+
+## .forEach(fn)
+
+Execute `fn` for each node in the object but unlike `.map()`, when
+`this.update()` is called it updates the object in-place.
+
+## .reduce(fn, acc)
+
+For each node in the object, perform a
+[left-fold](http://en.wikipedia.org/wiki/Fold_(higher-order_function))
+with the return value of `fn(acc, node)`.
+
+If `acc` isn't specified, `acc` is set to the root object for the first step
+and the root element is skipped.
+
+## .paths()
+
+Return an `Array` of every possible non-cyclic path in the object.
+Paths are `Array`s of string keys.
+
+## .nodes()
+
+Return an `Array` of every node in the object.
+
+## .clone()
+
+Create a deep clone of the object.
+
+## .get(path)
+
+Get the element at the array `path`.
+
+## .set(path, value)
+
+Set the element at the array `path` to `value`.
+
+## .has(path)
+
+Return whether the element at the array `path` exists.
+
+# context
+
+Each method that takes a callback has a context (its `this` object) with these
+attributes:
+
+## this.node
+
+The present node on the recursive walk
+
+## this.path
+
+An array of string keys from the root to the present node
+
+## this.parent
+
+The context of the node's parent.
+This is `undefined` for the root node.
+
+## this.key
+
+The name of the key of the present node in its parent.
+This is `undefined` for the root node.
+
+## this.isRoot, this.notRoot
+
+Whether the present node is the root node
+
+## this.isLeaf, this.notLeaf
+
+Whether or not the present node is a leaf node (has no children)
+
+## this.level
+
+Depth of the node within the traversal
+
+## this.circular
+
+If the node equals one of its parents, the `circular` attribute is set to the
+context of that parent and the traversal progresses no deeper.
+
+## this.update(value, stopHere=false)
+
+Set a new value for the present node.
+
+All the elements in `value` will be recursively traversed unless `stopHere` is
+true.
+
+## this.remove(stopHere=false)
+
+Remove the current element from the output. If the node is in an Array it will
+be spliced off. Otherwise it will be deleted from its parent.
+
+## this.delete(stopHere=false)
+
+Delete the current element from its parent in the output. Calls `delete` even on
+Arrays.
+
+## this.before(fn)
+
+Call this function before any of the children are traversed.
+
+You can assign into `this.keys` here to traverse in a custom order.
+
+## this.after(fn)
+
+Call this function after any of the children are traversed.
+
+## this.pre(fn)
+
+Call this function before each of the children are traversed.
+
+## this.post(fn)
+
+Call this function after each of the children are traversed.
+
+
+# install
+
+Using [npm](http://npmjs.org) do:
+
+ $ npm install traverse
+
+# license
+
+MIT
View
117 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/circular.js
@@ -0,0 +1,117 @@
+var test = require('tape');
+var traverse = require('../');
+var deepEqual = require('./lib/deep_equal');
+var util = require('util');
+
+test('circular', function (t) {
+ t.plan(1);
+
+ var obj = { x : 3 };
+ obj.y = obj;
+ traverse(obj).forEach(function (x) {
+ if (this.path.join('') == 'y') {
+ t.equal(
+ util.inspect(this.circular.node),
+ util.inspect(obj)
+ );
+ }
+ });
+});
+
+test('deepCirc', function (t) {
+ t.plan(2);
+ var obj = { x : [ 1, 2, 3 ], y : [ 4, 5 ] };
+ obj.y[2] = obj;
+
+ var times = 0;
+ traverse(obj).forEach(function (x) {
+ if (this.circular) {
+ t.same(this.circular.path, []);
+ t.same(this.path, [ 'y', 2 ]);
+ }
+ });
+});
+
+test('doubleCirc', function (t) {
+ var obj = { x : [ 1, 2, 3 ], y : [ 4, 5 ] };
+ obj.y[2] = obj;
+ obj.x.push(obj.y);
+
+ var circs = [];
+ traverse(obj).forEach(function (x) {
+ if (this.circular) {
+ circs.push({ circ : this.circular, self : this, node : x });
+ }
+ });
+
+ t.same(circs[0].self.path, [ 'x', 3, 2 ]);
+ t.same(circs[0].circ.path, []);
+
+ t.same(circs[1].self.path, [ 'y', 2 ]);
+ t.same(circs[1].circ.path, []);
+
+ t.same(circs.length, 2);
+ t.end();
+});
+
+test('circDubForEach', function (t) {
+ var obj = { x : [ 1, 2, 3 ], y : [ 4, 5 ] };
+ obj.y[2] = obj;
+ obj.x.push(obj.y);
+
+ traverse(obj).forEach(function (x) {
+ if (this.circular) this.update('...');
+ });
+
+ t.same(obj, { x : [ 1, 2, 3, [ 4, 5, '...' ] ], y : [ 4, 5, '...' ] });
+ t.end();
+});
+
+test('circDubMap', function (t) {
+ var obj = { x : [ 1, 2, 3 ], y : [ 4, 5 ] };
+ obj.y[2] = obj;
+ obj.x.push(obj.y);
+
+ var c = traverse(obj).map(function (x) {
+ if (this.circular) {
+ this.update('...');
+ }
+ });
+
+ t.same(c, { x : [ 1, 2, 3, [ 4, 5, '...' ] ], y : [ 4, 5, '...' ] });
+ t.end();
+});
+
+test('circClone', function (t) {
+ var obj = { x : [ 1, 2, 3 ], y : [ 4, 5 ] };
+ obj.y[2] = obj;
+ obj.x.push(obj.y);
+
+ var clone = traverse.clone(obj);
+ t.ok(obj !== clone);
+
+ t.ok(clone.y[2] === clone);
+ t.ok(clone.y[2] !== obj);
+ t.ok(clone.x[3][2] === clone);
+ t.ok(clone.x[3][2] !== obj);
+ t.same(clone.x.slice(0,3), [1,2,3]);
+ t.same(clone.y.slice(0,2), [4,5]);
+ t.end();
+});
+
+test('circMapScrub', function (t) {
+ var obj = { a : 1, b : 2 };
+ obj.c = obj;
+
+ var scrubbed = traverse(obj).map(function (node) {
+ if (this.circular) this.remove();
+ });
+ t.same(
+ Object.keys(scrubbed).sort(),
+ [ 'a', 'b' ]
+ );
+ t.ok(deepEqual(scrubbed, { a : 1, b : 2 }));
+
+ t.equal(obj.c, obj);
+ t.end();
+});
View
37 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/date.js
@@ -0,0 +1,37 @@
+var test = require('tape');
+var traverse = require('../');
+
+test('dateEach', function (t) {
+ var obj = { x : new Date, y : 10, z : 5 };
+
+ var counts = {};
+
+ traverse(obj).forEach(function (node) {
+ var t = (node instanceof Date && 'Date') || typeof node;
+ counts[t] = (counts[t] || 0) + 1;
+ });
+
+ t.same(counts, {
+ object : 1,
+ Date : 1,
+ number : 2,
+ });
+ t.end();
+});
+
+test('dateMap', function (t) {
+ var obj = { x : new Date, y : 10, z : 5 };
+
+ var res = traverse(obj).map(function (node) {
+ if (typeof node === 'number') this.update(node + 100);
+ });
+
+ t.ok(obj.x !== res.x);
+ t.same(res, {
+ x : obj.x,
+ y : 110,
+ z : 105,
+ });
+ t.end();
+});
+
View
240 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/equal.js
@@ -0,0 +1,240 @@
+var test = require('tape');
+var traverse = require('../');
+var deepEqual = require('./lib/deep_equal');
+
+test('deepDates', function (t) {
+ t.plan(2);
+
+ t.ok(
+ deepEqual(
+ { d : new Date, x : [ 1, 2, 3 ] },
+ { d : new Date, x : [ 1, 2, 3 ] }
+ ),
+ 'dates should be equal'
+ );
+
+ var d0 = new Date;
+ setTimeout(function () {
+ t.ok(
+ !deepEqual(
+ { d : d0, x : [ 1, 2, 3 ], },
+ { d : new Date, x : [ 1, 2, 3 ] }
+ ),
+ 'microseconds should count in date equality'
+ );
+ }, 5);
+});
+
+test('deepCircular', function (t) {
+ var a = [1];
+ a.push(a); // a = [ 1, *a ]
+
+ var b = [1];
+ b.push(a); // b = [ 1, [ 1, *a ] ]
+
+ t.ok(
+ !deepEqual(a, b),
+ 'circular ref mount points count towards equality'
+ );
+
+ var c = [1];
+ c.push(c); // c = [ 1, *c ]
+ t.ok(
+ deepEqual(a, c),
+ 'circular refs are structurally the same here'
+ );
+
+ var d = [1];
+ d.push(a); // c = [ 1, [ 1, *d ] ]
+ t.ok(
+ deepEqual(b, d),
+ 'non-root circular ref structural comparison'
+ );
+
+ t.end();
+});
+
+test('deepInstances', function (t) {
+ t.ok(
+ !deepEqual([ new Boolean(false) ], [ false ]),
+ 'boolean instances are not real booleans'
+ );
+
+ t.ok(
+ !deepEqual([ new String('x') ], [ 'x' ]),
+ 'string instances are not real strings'
+ );
+
+ t.ok(
+ !deepEqual([ new Number(4) ], [ 4 ]),
+ 'number instances are not real numbers'
+ );
+
+ t.ok(
+ deepEqual([ new RegExp('x') ], [ /x/ ]),
+ 'regexp instances are real regexps'
+ );
+
+ t.ok(
+ !deepEqual([ new RegExp(/./) ], [ /../ ]),
+ 'these regexps aren\'t the same'
+ );
+
+ t.ok(
+ !deepEqual(
+ [ function (x) { return x * 2 } ],
+ [ function (x) { return x * 2 } ]
+ ),
+ 'functions with the same .toString() aren\'t necessarily the same'
+ );
+
+ var f = function (x) { return x * 2 };
+ t.ok(
+ deepEqual([ f ], [ f ]),
+ 'these functions are actually equal'
+ );
+
+ t.end();
+});
+
+test('deepEqual', function (t) {
+ t.ok(
+ !deepEqual([ 1, 2, 3 ], { 0 : 1, 1 : 2, 2 : 3 }),
+ 'arrays are not objects'
+ );
+ t.end();
+});
+
+test('falsy', function (t) {
+ t.ok(
+ !deepEqual([ undefined ], [ null ]),
+ 'null is not undefined!'
+ );
+
+ t.ok(
+ !deepEqual([ null ], [ undefined ]),
+ 'undefined is not null!'
+ );
+
+ t.ok(
+ !deepEqual(
+ { a : 1, b : 2, c : [ 3, undefined, 5 ] },
+ { a : 1, b : 2, c : [ 3, null, 5 ] }
+ ),
+ 'undefined is not null, however deeply!'
+ );
+
+ t.ok(
+ !deepEqual(
+ { a : 1, b : 2, c : [ 3, undefined, 5 ] },
+ { a : 1, b : 2, c : [ 3, null, 5 ] }
+ ),
+ 'null is not undefined, however deeply!'
+ );
+
+ t.ok(
+ !deepEqual(
+ { a : 1, b : 2, c : [ 3, undefined, 5 ] },
+ { a : 1, b : 2, c : [ 3, null, 5 ] }
+ ),
+ 'null is not undefined, however deeply!'
+ );
+
+ t.end();
+});
+
+test('deletedArrayEqual', function (t) {
+ var xs = [ 1, 2, 3, 4 ];
+ delete xs[2];
+
+ var ys = Object.create(Array.prototype);
+ ys[0] = 1;
+ ys[1] = 2;
+ ys[3] = 4;
+
+ t.ok(
+ deepEqual(xs, ys),
+ 'arrays with deleted elements are only equal to'
+ + ' arrays with similarly deleted elements'
+ );
+
+ t.ok(
+ !deepEqual(xs, [ 1, 2, undefined, 4 ]),
+ 'deleted array elements cannot be undefined'
+ );
+
+ t.ok(
+ !deepEqual(xs, [ 1, 2, null, 4 ]),
+ 'deleted array elements cannot be null'
+ );
+
+ t.end();
+});
+
+test('deletedObjectEqual', function (t) {
+ var obj = { a : 1, b : 2, c : 3 };
+ delete obj.c;
+
+ t.ok(
+ deepEqual(obj, { a : 1, b : 2 }),
+ 'deleted object elements should not show up'
+ );
+
+ t.ok(
+ !deepEqual(obj, { a : 1, b : 2, c : undefined }),
+ 'deleted object elements are not undefined'
+ );
+
+ t.ok(
+ !deepEqual(obj, { a : 1, b : 2, c : null }),
+ 'deleted object elements are not null'
+ );
+
+ t.end();
+});
+
+test('emptyKeyEqual', function (t) {
+ t.ok(!deepEqual(
+ { a : 1 }, { a : 1, '' : 55 }
+ ));
+
+ t.end();
+});
+
+test('deepArguments', function (t) {
+ t.ok(
+ !deepEqual(
+ [ 4, 5, 6 ],
+ (function () { return arguments })(4, 5, 6)
+ ),
+ 'arguments are not arrays'
+ );
+
+ t.ok(
+ deepEqual(
+ (function () { return arguments })(4, 5, 6),
+ (function () { return arguments })(4, 5, 6)
+ ),
+ 'arguments should equal'
+ );
+
+ t.end();
+});
+
+test('deepUn', function (t) {
+ t.ok(!deepEqual({ a : 1, b : 2 }, undefined));
+ t.ok(!deepEqual({ a : 1, b : 2 }, {}));
+ t.ok(!deepEqual(undefined, { a : 1, b : 2 }));
+ t.ok(!deepEqual({}, { a : 1, b : 2 }));
+ t.ok(deepEqual(undefined, undefined));
+ t.ok(deepEqual(null, null));
+ t.ok(!deepEqual(undefined, null));
+
+ t.end();
+});
+
+test('deepLevels', function (t) {
+ var xs = [ 1, 2, [ 3, 4, [ 5, 6 ] ] ];
+ t.ok(!deepEqual(xs, []));
+ t.end();
+});
View
11 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/error.js
@@ -0,0 +1,11 @@
+var test = require('tape');
+var traverse = require('../');
+
+test('traverse an Error', function (t) {
+ var obj = new Error("test");
+ var results = traverse(obj).map(function (node) {});
+ t.same(results, { message: 'test' });
+
+ t.end();
+});
+
View
15 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/has.js
@@ -0,0 +1,15 @@
+var test = require('tape');
+var traverse = require('../');
+
+test('has', function (t) {
+ var obj = { a : 2, b : [ 4, 5, { c : 6 } ] };
+
+ t.equal(traverse(obj).has([ 'b', 2, 'c' ]), true)
+ t.equal(traverse(obj).has([ 'b', 2, 'c', 0 ]), false)
+ t.equal(traverse(obj).has([ 'b', 2, 'd' ]), false)
+ t.equal(traverse(obj).has([]), true)
+ t.equal(traverse(obj).has([ 'a' ]), true)
+ t.equal(traverse(obj).has([ 'a', 2 ]), false)
+
+ t.end();
+});
View
17 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/instance.js
@@ -0,0 +1,17 @@
+var test = require('tape');
+var traverse = require('../');
+var EventEmitter = require('events').EventEmitter;
+
+test('check instanceof on node elems', function (t) {
+ var counts = { emitter : 0 };
+
+ traverse([ new EventEmitter, 3, 4, { ev : new EventEmitter }])
+ .forEach(function (node) {
+ if (node instanceof EventEmitter) counts.emitter ++;
+ })
+ ;
+
+ t.equal(counts.emitter, 2);
+
+ t.end();
+});
View
43 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/interface.js
@@ -0,0 +1,43 @@
+var test = require('tape');
+var traverse = require('../');
+
+test('interface map', function (t) {
+ var obj = { a : [ 5,6,7 ], b : { c : [8] } };
+
+ t.same(
+ traverse.paths(obj)
+ .sort()
+ .map(function (path) { return path.join('/') })
+ .slice(1)
+ .join(' ')
+ ,
+ 'a a/0 a/1 a/2 b b/c b/c/0'
+ );
+
+ t.same(
+ traverse.nodes(obj),
+ [
+ { a: [ 5, 6, 7 ], b: { c: [ 8 ] } },
+ [ 5, 6, 7 ], 5, 6, 7,
+ { c: [ 8 ] }, [ 8 ], 8
+ ]
+ );
+
+ t.same(
+ traverse.map(obj, function (node) {
+ if (typeof node == 'number') {
+ return node + 1000;
+ }
+ else if (Array.isArray(node)) {
+ return node.join(' ');
+ }
+ }),
+ { a: '5 6 7', b: { c: '8' } }
+ );
+
+ var nodes = 0;
+ traverse.forEach(obj, function (node) { nodes ++ });
+ t.same(nodes, 8);
+
+ t.end();
+});
View
49 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/json.js
@@ -0,0 +1,49 @@
+var test = require('tape');
+var traverse = require('../');
+
+test('json test', function (t) {
+ var id = 54;
+ var callbacks = {};
+ var obj = { moo : function () {}, foo : [2,3,4, function () {}] };
+
+ var scrubbed = traverse(obj).map(function (x) {
+ if (typeof x === 'function') {
+ callbacks[id] = { id : id, f : x, path : this.path };
+ this.update('[Function]');
+ id++;
+ }
+ });
+
+ t.equal(
+ scrubbed.moo, '[Function]',
+ 'obj.moo replaced with "[Function]"'
+ );
+
+ t.equal(
+ scrubbed.foo[3], '[Function]',
+ 'obj.foo[3] replaced with "[Function]"'
+ );
+
+ t.same(scrubbed, {
+ moo : '[Function]',
+ foo : [ 2, 3, 4, "[Function]" ]
+ }, 'Full JSON string matches');
+
+ t.same(
+ typeof obj.moo, 'function',
+ 'Original obj.moo still a function'
+ );
+
+ t.same(
+ typeof obj.foo[3], 'function',
+ 'Original obj.foo[3] still a function'
+ );
+
+ t.same(callbacks, {
+ 54: { id: 54, f : obj.moo, path: [ 'moo' ] },
+ 55: { id: 55, f : obj.foo[3], path: [ 'foo', '3' ] },
+ }, 'Check the generated callbacks list');
+
+ t.end();
+});
+
View
31 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/keys.js
@@ -0,0 +1,31 @@
+var test = require('tape');
+var traverse = require('../');
+
+test('sort test', function (t) {
+ var acc = [];
+ traverse({
+ a: 30,
+ b: 22,
+ id: 9
+ }).forEach(function (node) {
+ if ((! Array.isArray(node)) && typeof node === 'object') {
+ this.before(function(node) {
+ this.keys = Object.keys(node);
+ this.keys.sort(function(a, b) {
+ a = [a === "id" ? 0 : 1, a];
+ b = [b === "id" ? 0 : 1, b];
+ return a < b ? -1 : a > b ? 1 : 0;
+ });
+ });
+ }
+ if (this.isLeaf) acc.push(node);
+ });
+
+ t.equal(
+ acc.join(' '),
+ '9 30 22',
+ 'Traversal in a custom order'
+ );
+
+ t.end();
+});
View
22 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/leaves.js
@@ -0,0 +1,22 @@
+var test = require('tape');
+var traverse = require('../');
+
+test('leaves test', function (t) {
+ var acc = [];
+ traverse({
+ a : [1,2,3],
+ b : 4,
+ c : [5,6],
+ d : { e : [7,8], f : 9 }
+ }).forEach(function (x) {
+ if (this.isLeaf) acc.push(x);
+ });
+
+ t.equal(
+ acc.join(' '),
+ '1 2 3 4 5 6 7 8 9',
+ 'Traversal in the right(?) order'
+ );
+
+ t.end();
+});
View
96 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/lib/deep_equal.js
@@ -0,0 +1,96 @@
+var traverse = require('../../');
+
+module.exports = function (a, b) {
+ if (arguments.length !== 2) {
+ throw new Error(
+ 'deepEqual requires exactly two objects to compare against'
+ );
+ }
+
+ var equal = true;
+ var node = b;
+
+ traverse(a).forEach(function (y) {
+ var notEqual = (function () {
+ equal = false;
+ //this.stop();
+ return undefined;
+ }).bind(this);
+
+ //if (node === undefined || node === null) return notEqual();
+
+ if (!this.isRoot) {
+ /*
+ if (!Object.hasOwnProperty.call(node, this.key)) {
+ return notEqual();
+ }
+ */
+ if (typeof node !== 'object') return notEqual();
+ node = node[this.key];
+ }
+
+ var x = node;
+
+ this.post(function () {
+ node = x;
+ });
+
+ var toS = function (o) {
+ return Object.prototype.toString.call(o);
+ };
+
+ if (this.circular) {
+ if (traverse(b).get(this.circular.path) !== x) notEqual();
+ }
+ else if (typeof x !== typeof y) {
+ notEqual();
+ }
+ else if (x === null || y === null || x === undefined || y === undefined) {
+ if (x !== y) notEqual();
+ }
+ else if (x.__proto__ !== y.__proto__) {
+ notEqual();
+ }
+ else if (x === y) {
+ // nop
+ }
+ else if (typeof x === 'function') {
+ if (x instanceof RegExp) {
+ // both regexps on account of the __proto__ check
+ if (x.toString() != y.toString()) notEqual();
+ }
+ else if (x !== y) notEqual();
+ }
+ else if (typeof x === 'object') {
+ if (toS(y) === '[object Arguments]'
+ || toS(x) === '[object Arguments]') {
+ if (toS(x) !== toS(y)) {
+ notEqual();
+ }
+ }
+ else if (toS(y) === '[object RegExp]'
+ || toS(x) === '[object RegExp]') {
+ if (!x || !y || x.toString() !== y.toString()) notEqual();
+ }
+ else if (x instanceof Date || y instanceof Date) {
+ if (!(x instanceof Date) || !(y instanceof Date)
+ || x.getTime() !== y.getTime()) {
+ notEqual();
+ }
+ }
+ else {
+ var kx = Object.keys(x);
+ var ky = Object.keys(y);
+ if (kx.length !== ky.length) return notEqual();
+ for (var i = 0; i < kx.length; i++) {
+ var k = kx[i];
+ if (!Object.hasOwnProperty.call(y, k)) {
+ notEqual();
+ }
+ }
+ }
+ }
+ });
+
+ return equal;
+};
View
300 test/modules-checked-in/node_modules/hashish/node_modules/traverse/test/mutability.js
@@ -0,0 +1,300 @@
+var test = require('tape');
+var traverse = require('../');
+var deepEqual = require('./lib/deep_equal');
+
+test('mutate', function (t) {
+ var obj = { a : 1, b : 2, c : [ 3, 4 ] };
+ var res = traverse(obj).forEach(function (x) {
+ if (typeof x === 'number' && x % 2 === 0) {
+ this.update(x * 10);
+ }
+ });
+ t.same(obj, res);
+ t.same(obj, { a : 1, b : 20, c : [ 3, 40 ] });
+ t.end();
+});
+
+test('mutateT', function (t) {
+ var obj = { a : 1, b : 2, c : [ 3, 4 ] };
+ var res = traverse.forEach(obj, function (x) {
+ if (typeof x === 'number' && x % 2 === 0) {
+ this.update(x * 10);
+ }
+ });
+ t.same(obj, res);
+ t.same(obj, { a : 1, b : 20, c : [ 3, 40 ] });
+ t.end();
+});
+
+test('map', function (t) {
+ var obj = { a : 1, b : 2, c : [ 3, 4 ] };
+ var res = traverse(obj).map(function (x) {
+ if (typeof x === 'number' && x % 2 === 0) {
+ this.update(x * 10);
+ }
+ });
+ t.same(obj, { a : 1, b : 2, c : [ 3, 4 ] });
+ t.same(res, { a : 1, b : 20, c : [ 3, 40 ] });
+ t.end();
+});
+
+test('mapT', function (t) {
+ var obj = { a : 1, b : 2, c : [ 3, 4 ] };
+ var res = traverse.map(obj, function (x) {
+ if (typeof x === 'number' && x % 2 === 0) {
+ this.update(x * 10);
+ }
+ });
+ t.same(obj, { a : 1, b : 2, c : [ 3, 4 ] });
+ t.same(res, { a : 1, b : 20, c : [ 3, 40 ] });
+ t.end();
+});
+
+test('clone', function (t) {
+ var obj = { a : 1, b : 2, c : [ 3, 4 ] };
+ var res = traverse(obj).clone();
+ t.same(obj, res);
+ t.ok(obj !== res);
+ obj.a ++;
+ t.same(res.a, 1);
+ obj.c.push(5);
+ t.same(res.c, [ 3, 4 ]);
+ t.end();
+});
+
+test('cloneT', function (t) {
+ var obj = { a : 1, b : 2, c : [ 3, 4 ] };
+ var res = traverse.clone(obj);
+ t.same(obj, res);
+ t.ok(obj !== res);
+ obj.a ++;
+ t.same(res.a, 1);
+ obj.c.push(5);
+ t.same(res.c, [ 3, 4 ]);
+ t.end();
+});
+
+test('reduce', function (t) {
+ var obj = { a : 1, b : 2, c : [ 3, 4 ] };
+ var res = traverse(obj).reduce(function (acc, x) {
+ if (this.isLeaf) acc.push(x);
+ return acc;
+ }, []);
+ t.same(obj, { a : 1, b : 2, c : [ 3, 4 ] });
+ t.same(res, [ 1, 2, 3, 4 ]);
+ t.end();
+});
+
+test('reduceInit', function (t) {
+ var obj = { a : 1, b : 2, c : [ 3, 4 ] };
+ var res = traverse(obj).reduce(function (acc, x) {
+ if (this.isRoot) assert.fail('got root');
+ return acc;
+ });
+ t.same(obj, { a : 1, b : 2, c : [ 3, 4 ] });
+ t.same(res, obj);
+ t.end();
+});
+
+test('remove', function (t) {
+ var obj = { a : 1, b : 2, c : [ 3, 4 ] };
+ traverse(obj).forEach(function (x) {
+ if (this.isLeaf && x % 2 == 0) this.remove();
+ });
+
+ t.same(obj, { a : 1, c : [ 3 ] });
+ t.end();
+});
+
+exports.removeNoStop = function() {
+ var obj = { a : 1, b : 2, c : { d: 3, e: 4 }, f: 5 };
+
+ var keys = [];
+ traverse(obj).forEach(function (x) {
+ keys.push(this.key)
+ if (this.key == 'c') this.remove();
+ });
+
+ t.same(keys, [undefined, 'a', 'b', 'c', 'd', 'e', 'f'])
+ t.end();
+}
+
+exports.removeStop = function() {
+ var obj = { a : 1, b : 2, c : { d: 3, e: 4 }, f: 5 };
+
+ var keys = [];
+ traverse(obj).forEach(function (x) {
+ keys.push(this.key)
+ if (this.key == 'c') this.remove(true);
+ });
+
+ t.same(keys, [undefined, 'a', 'b', 'c', 'f'])
+ t.end();
+}
+
+test('removeMap', function (t) {
+ var obj = { a : 1, b : 2, c : [ 3, 4 ] };
+ var res = traverse(obj).map(function (x) {
+ if (this.isLeaf && x % 2 == 0) this.remove();
+ });
+
+ t.same(obj, { a : 1, b : 2, c : [ 3, 4 ] });
+ t.same(res, { a : 1, c : [ 3 ] });
+ t.end();
+});
+
+test('delete', function (t) {
+ var obj = { a : 1, b : 2, c : [ 3, 4 ] };
+ traverse(obj).forEach(function (x) {
+ if (this.isLeaf && x % 2 == 0) this.delete();
+ });
+
+ t.ok(!deepEqual(
+ obj, { a : 1, c : [ 3, undefined ] }
+ ));
+
+ t.ok(deepEqual(
+ obj, { a : 1, c : [ 3 ] }
+ ));
+
+ t.ok(!deepEqual(
+ obj, { a : 1, c : [ 3, null ] }
+ ));
+ t.end();
+});
+
+test('deleteNoStop', function (t) {
+ var obj = { a : 1, b : 2, c : { d: 3, e: 4 } };
+
+ var keys = [];
+ traverse(obj).forEach(function (x) {
+ keys.push(this.key)
+ if (this.key == 'c') this.delete();
+ });
+
+ t.same(keys, [undefined, 'a', 'b', 'c', 'd', 'e'])
+ t.end();
+});
+
+test('deleteStop', function (t) {
+ var obj = { a : 1, b : 2, c : { d: 3, e: 4 } };
+
+ var keys = [];
+ traverse(obj).forEach(function (x) {
+ keys.push(this.key)
+ if (this.key == 'c') this.delete(true);
+ });
+
+ t.same(keys, [undefined, 'a', 'b', 'c'])
+ t.end();
+});
+
+test('deleteRedux', function (t) {
+ var obj = { a : 1, b : 2, c : [ 3, 4, 5 ] };
+ traverse(obj).forEach(function (x) {
+ if (this.isLeaf && x % 2 == 0) this.delete();
+ });
+
+ t.ok(!deepEqual(
+ obj, { a : 1, c : [ 3, undefined, 5 ] }
+ ));
+
+ t.ok(deepEqual(
+ obj, { a : 1, c : [ 3 ,, 5 ] }
+ ));
+
+ t.ok(!deepEqual(
+ obj, { a : 1, c : [ 3, null, 5 ] }
+ ));
+
+ t.ok(!deepEqual(
+ obj, { a : 1, c : [ 3, 5 ] }
+ ));
+
+ t.end();
+});