Comparing version 0.6.6 to 0.6.7
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var traverse = require('traverse'); | ||
@@ -5,10 +7,10 @@ | ||
var callbacks = {}; | ||
var obj = { moo : function () {}, foo : [2,3,4, function () {}] }; | ||
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++; | ||
} | ||
if (typeof x === 'function') { | ||
callbacks[id] = { id: id, f: x, path: this.path }; | ||
this.update('[Function]'); | ||
id++; | ||
} | ||
}); | ||
@@ -15,0 +17,0 @@ |
@@ -0,15 +1,17 @@ | ||
'use strict'; | ||
var traverse = require('traverse'); | ||
var obj = { | ||
a : [1,2,3], | ||
b : 4, | ||
c : [5,6], | ||
d : { e : [7,8], f : 9 }, | ||
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; | ||
if (this.isLeaf) { acc.push(x); } | ||
return acc; | ||
}, []); | ||
console.dir(leaves); |
@@ -0,8 +1,10 @@ | ||
'use strict'; | ||
var traverse = require('traverse'); | ||
var obj = [ 5, 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ]; | ||
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); | ||
if (x < 0) { this.update(x + 128); } | ||
}); | ||
console.dir(obj); |
@@ -0,10 +1,12 @@ | ||
'use strict'; | ||
// scrub out circular references | ||
var traverse = require('traverse'); | ||
var obj = { a : 1, b : 2, c : [ 3, 4 ] }; | ||
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() | ||
var scrubbed = traverse(obj).map(function () { | ||
if (this.circular) { this.remove(); } | ||
}); | ||
console.dir(scrubbed); |
#!/usr/bin/env node | ||
'use strict'; | ||
var traverse = require('traverse'); | ||
var obj = [ 'five', 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ]; | ||
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(); | ||
} | ||
traverse(obj).forEach(function toS(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) { | ||
toS(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(); | ||
} | ||
}); | ||
@@ -36,0 +35,0 @@ |
545
index.js
@@ -1,314 +0,311 @@ | ||
var traverse = module.exports = function (obj) { | ||
return new Traverse(obj); | ||
'use strict'; | ||
// TODO: use call-bind, is-date, is-regex, is-string, is-boolean-object, is-number-object | ||
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]'; } | ||
// TODO: use isarray | ||
var isArray = Array.isArray || function isArray(xs) { | ||
return Object.prototype.toString.call(xs) === '[object Array]'; | ||
}; | ||
function Traverse (obj) { | ||
this.value = obj; | ||
// TODO: use for-each? | ||
function forEach(xs, fn) { | ||
if (xs.forEach) { return xs.forEach(fn); } | ||
for (var i = 0; i < xs.length; i++) { | ||
fn(xs[i], i, xs); | ||
} | ||
return void undefined; | ||
} | ||
// TODO: use object-keys | ||
var objectKeys = Object.keys || function keys(obj) { | ||
var res = []; | ||
for (var key in obj) { res.push(key); } // eslint-disable-line no-restricted-syntax | ||
return res; | ||
}; | ||
// TODO: use object.hasown | ||
var hasOwnProperty = Object.prototype.hasOwnProperty || function (obj, key) { | ||
return key in obj; | ||
}; | ||
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) || isNumber(src) || isString(src)) { | ||
dst = Object(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() {}; // eslint-disable-line func-style, func-name-matching | ||
T.prototype = proto; | ||
dst = new T(); | ||
} | ||
forEach(objectKeys(src), function (key) { | ||
dst[key] = src[key]; | ||
}); | ||
return dst; | ||
} | ||
return src; | ||
} | ||
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[path.length - 1], | ||
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; // eslint-disable-line no-restricted-syntax | ||
} | ||
} | ||
} 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 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; | ||
var node = this.value; | ||
for (var i = 0; i < ps.length; i++) { | ||
var key = ps[i]; | ||
if (!node || !hasOwnProperty.call(node, key)) { | ||
return void undefined; | ||
} | ||
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; | ||
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; | ||
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); | ||
return walk(this.value, cb, true); | ||
}; | ||
Traverse.prototype.forEach = function (cb) { | ||
this.value = walk(this.value, cb, false); | ||
return this.value; | ||
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; | ||
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; | ||
var acc = []; | ||
this.forEach(function () { | ||
acc.push(this.path); | ||
}); | ||
return acc; | ||
}; | ||
Traverse.prototype.nodes = function () { | ||
var acc = []; | ||
this.forEach(function (x) { | ||
acc.push(this.node); | ||
}); | ||
return acc; | ||
var acc = []; | ||
this.forEach(function () { | ||
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); | ||
}; | ||
var parents = []; | ||
var nodes = []; | ||
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; | ||
} | ||
return (function clone(src) { | ||
for (var i = 0; i < parents.length; i++) { | ||
if (parents[i] === src) { | ||
return nodes[i]; | ||
} | ||
} | ||
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; | ||
} | ||
if (typeof src === 'object' && src !== null) { | ||
var dst = copy(src); | ||
var objectKeys = Object.keys || function keys (obj) { | ||
var res = []; | ||
for (var key in obj) res.push(key) | ||
return res; | ||
}; | ||
parents.push(src); | ||
nodes.push(dst); | ||
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]' } | ||
forEach(objectKeys(src), function (key) { | ||
dst[key] = clone(src[key]); | ||
}); | ||
var isArray = Array.isArray || function isArray (xs) { | ||
return Object.prototype.toString.call(xs) === '[object Array]'; | ||
}; | ||
parents.pop(); | ||
nodes.pop(); | ||
return dst; | ||
} | ||
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); | ||
} | ||
return src; | ||
}(this.value)); | ||
}; | ||
function traverse(obj) { | ||
return new Traverse(obj); | ||
} | ||
// TODO: replace with object.assign? | ||
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); | ||
}; | ||
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; | ||
}; | ||
module.exports = traverse; |
135
package.json
{ | ||
"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" | ||
"name": "traverse", | ||
"version": "0.6.7", | ||
"description": "traverse and transform objects by visiting every node on a recursive walk", | ||
"main": "index.js", | ||
"directories": { | ||
"example": "example", | ||
"test": "test" | ||
}, | ||
"devDependencies": { | ||
"@ljharb/eslint-config": "^21.0.0", | ||
"aud": "^2.0.1", | ||
"auto-changelog": "^2.4.0", | ||
"eslint": "=8.8.0", | ||
"in-publish": "^2.0.1", | ||
"npmignore": "^0.3.0", | ||
"safe-publish-latest": "^2.0.0", | ||
"tape": "^5.6.1" | ||
}, | ||
"scripts": { | ||
"prepack": "npmignore --auto --commentLines=autogenerated", | ||
"prepublishOnly": "safe-publish-latest", | ||
"prepublish": "not-in-publish || npm run prepublishOnly", | ||
"lint": "eslint --ext=js,mjs .", | ||
"pretest": "npm run lint", | ||
"tests-only": "tape 'test/**/*.js'", | ||
"test": "npm run tests-only", | ||
"posttest": "aud --production", | ||
"version": "auto-changelog && git add CHANGELOG.md", | ||
"postversion": "auto-changelog && git add CHANGELOG.md && git commit --no-edit --amend && git tag -f \"v$(node -e \"console.log(require('./package.json').version)\")\"" | ||
}, | ||
"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/ljharb/js-traverse.git" | ||
}, | ||
"homepage": "https://github.com/ljharb/js-traverse", | ||
"keywords": [ | ||
"traverse", | ||
"walk", | ||
"recursive", | ||
"map", | ||
"forEach", | ||
"deep", | ||
"clone" | ||
], | ||
"author": { | ||
"name": "James Halliday", | ||
"email": "mail@substack.net", | ||
"url": "http://substack.net" | ||
}, | ||
"funding": { | ||
"url": "https://github.com/sponsors/ljharb" | ||
}, | ||
"license": "MIT", | ||
"auto-changelog": { | ||
"output": "CHANGELOG.md", | ||
"template": "keepachangelog", | ||
"unreleased": false, | ||
"commitLimit": false, | ||
"backfillLimit": false, | ||
"hideCredit": true | ||
}, | ||
"publishConfig": { | ||
"ignore": [ | ||
".github/workflows" | ||
] | ||
} | ||
} |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var test = require('tape'); | ||
@@ -7,112 +9,111 @@ var traverse = require('../'); | ||
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) | ||
); | ||
} | ||
}); | ||
t.plan(1); | ||
var obj = { x: 3 }; | ||
obj.y = obj; | ||
traverse(obj).forEach(function () { | ||
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 ]); | ||
} | ||
}); | ||
t.plan(2); | ||
var obj = { x: [1, 2, 3], y: [4, 5] }; | ||
obj.y[2] = obj; | ||
traverse(obj).forEach(function () { | ||
if (this.circular) { | ||
t.deepEqual(this.circular.path, []); | ||
t.deepEqual(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(); | ||
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.deepEqual(circs[0].self.path, ['x', '3', '2']); | ||
t.deepEqual(circs[0].circ.path, []); | ||
t.deepEqual(circs[1].self.path, ['y', '2']); | ||
t.deepEqual(circs[1].circ.path, []); | ||
t.deepEqual(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(); | ||
var obj = { x: [1, 2, 3], y: [4, 5] }; | ||
obj.y[2] = obj; | ||
obj.x.push(obj.y); | ||
traverse(obj).forEach(function () { | ||
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(); | ||
var obj = { x: [1, 2, 3], y: [4, 5] }; | ||
obj.y[2] = obj; | ||
obj.x.push(obj.y); | ||
var c = traverse(obj).map(function () { | ||
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(); | ||
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(); | ||
var obj = { a: 1, b: 2 }; | ||
obj.c = obj; | ||
var scrubbed = traverse(obj).map(function () { | ||
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(); | ||
}); |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var test = require('tape'); | ||
@@ -5,34 +7,34 @@ 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(); | ||
var obj = { x: new Date(), y: 10, z: 5 }; | ||
var counts = {}; | ||
traverse(obj).forEach(function (node) { | ||
var type = (node instanceof Date && 'Date') || typeof node; | ||
counts[type] = (counts[type] || 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(); | ||
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(); | ||
}); | ||
@@ -0,240 +1,238 @@ | ||
'use strict'; | ||
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); | ||
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(); | ||
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(); | ||
t.ok( | ||
!deepEqual([Object(false)], [false]), | ||
'boolean instances are not real booleans' | ||
); | ||
t.ok( | ||
!deepEqual([Object('x')], ['x']), | ||
'string instances are not real strings' | ||
); | ||
t.ok( | ||
!deepEqual([Object(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' | ||
); | ||
function f(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(); | ||
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(); | ||
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(); | ||
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(); | ||
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(); | ||
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(); | ||
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(); | ||
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(); | ||
var xs = [1, 2, [3, 4, [5, 6]]]; | ||
t.ok(!deepEqual(xs, [])); | ||
t.end(); | ||
}); |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var test = require('tape'); | ||
@@ -5,8 +7,8 @@ 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(); | ||
var obj = new Error('test'); | ||
var results = traverse(obj).map(function () {}); | ||
t.same(results, { message: 'test' }); | ||
t.end(); | ||
}); | ||
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var test = require('tape'); | ||
@@ -5,12 +7,12 @@ 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(); | ||
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(); | ||
}); |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var test = require('tape'); | ||
@@ -6,13 +8,11 @@ var traverse = require('../'); | ||
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(); | ||
var counts = { emitter: 0 }; | ||
traverse([new EventEmitter(), 3, 4, { ev: new EventEmitter() }]) | ||
.forEach(function (node) { | ||
if (node instanceof EventEmitter) { counts.emitter += 1; } | ||
}); | ||
t.equal(counts.emitter, 2); | ||
t.end(); | ||
}); |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var test = require('tape'); | ||
@@ -5,40 +7,41 @@ 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(); | ||
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; | ||
} | ||
if (Array.isArray(node)) { | ||
return node.join(' '); | ||
} | ||
return void undefined; | ||
}), | ||
{ a: '5 6 7', b: { c: '8' } } | ||
); | ||
var nodes = 0; | ||
traverse.forEach(obj, function () { nodes += 1; }); | ||
t.equal(nodes, 8); | ||
t.end(); | ||
}); |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var test = require('tape'); | ||
@@ -5,46 +7,50 @@ 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(); | ||
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 += 1; | ||
} | ||
}); | ||
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(); | ||
}); | ||
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var test = require('tape'); | ||
@@ -5,28 +7,28 @@ 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(); | ||
var acc = []; | ||
traverse({ | ||
a: 30, | ||
b: 22, | ||
id: 9, | ||
}).forEach(function (node) { | ||
if (!Array.isArray(node) && typeof node === 'object') { | ||
this.before(function (beforeNode) { | ||
this.keys = Object.keys(beforeNode); | ||
this.keys.sort(function (a, b) { | ||
var aA = [a === 'id' ? 0 : 1, a]; | ||
var bA = [b === 'id' ? 0 : 1, b]; | ||
return aA < bA ? -1 : aA > bA ? 1 : 0; | ||
}); | ||
}); | ||
} | ||
if (this.isLeaf) { acc.push(node); } | ||
}); | ||
t.equal( | ||
acc.join(' '), | ||
'9 30 22', | ||
'Traversal in a custom order' | ||
); | ||
t.end(); | ||
}); |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var test = require('tape'); | ||
@@ -5,19 +7,19 @@ 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(); | ||
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(); | ||
}); |
@@ -0,24 +1,29 @@ | ||
'use strict'; | ||
var traverse = require('../../'); | ||
function toS(o) { | ||
return Object.prototype.toString.call(o); | ||
} | ||
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 (arguments.length !== 2) { | ||
throw new Error('deepEqual requires exactly two objects to compare against'); | ||
} | ||
var equal = true; | ||
function notEqual() { | ||
equal = false; | ||
// this.stop(); | ||
return undefined; | ||
} | ||
var node = b; | ||
traverse(a).forEach(function (y) { // eslint-disable-line consistent-return | ||
// if (node === undefined || node === null) return notEqual(); | ||
if (!this.isRoot) { | ||
/* | ||
if (!Object.hasOwnProperty.call(node, this.key)) { | ||
@@ -28,70 +33,56 @@ 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]' | ||
if (typeof node !== 'object') { return notEqual(); } | ||
node = node[this.key]; | ||
} | ||
var x = node; | ||
this.post(function () { | ||
node = x; | ||
}); | ||
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 (String(x) !== String(y)) { 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]' | ||
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) | ||
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; | ||
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; | ||
}; |
@@ -0,2 +1,5 @@ | ||
'use strict'; | ||
var test = require('tape'); | ||
var assert = require('assert'); | ||
var traverse = require('../'); | ||
@@ -6,296 +9,269 @@ 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(); | ||
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(); | ||
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(); | ||
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(); | ||
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(); | ||
var obj = { a: 1, b: 2, c: [3, 4] }; | ||
var res = traverse(obj).clone(); | ||
t.same(obj, res); | ||
t.ok(obj !== res); | ||
obj.a += 1; | ||
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(); | ||
var obj = { a: 1, b: 2, c: [3, 4] }; | ||
var res = traverse.clone(obj); | ||
t.same(obj, res); | ||
t.ok(obj !== res); | ||
obj.a += 1; | ||
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(); | ||
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(); | ||
var obj = { a: 1, b: 2, c: [3, 4] }; | ||
var res = traverse(obj).reduce(function (acc) { | ||
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(); | ||
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(); | ||
}); | ||
test('removeNoStop', function (t) { | ||
var obj = { a: 1, b: 2, c: { d: 3, e: 4 }, f: 5 }; | ||
t.same(keys, [undefined, 'a', 'b', 'c', 'd', 'e', 'f']) | ||
t.end(); | ||
} | ||
var keys = []; | ||
traverse(obj).forEach(function () { | ||
keys.push(this.key); | ||
if (this.key === 'c') { this.remove(); } | ||
}); | ||
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', 'd', 'e', 'f']); | ||
t.end(); | ||
}); | ||
t.same(keys, [undefined, 'a', 'b', 'c', 'f']) | ||
t.end(); | ||
} | ||
test('removeStop', function (t) { | ||
var obj = { a: 1, b: 2, c: { d: 3, e: 4 }, f: 5 }; | ||
var keys = []; | ||
traverse(obj).forEach(function () { | ||
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(); | ||
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(); | ||
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(); | ||
}); | ||
var obj = { a: 1, b: 2, c: { d: 3, e: 4 } }; | ||
t.same(keys, [undefined, 'a', 'b', 'c', 'd', 'e']) | ||
t.end(); | ||
var keys = []; | ||
traverse(obj).forEach(function () { | ||
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); | ||
}); | ||
var obj = { a: 1, b: 2, c: { d: 3, e: 4 } }; | ||
t.same(keys, [undefined, 'a', 'b', 'c']) | ||
t.end(); | ||
var keys = []; | ||
traverse(obj).forEach(function () { | ||
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(); | ||
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(); | ||
}); | ||
test('deleteMap', 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.delete(); | ||
}); | ||
t.ok(deepEqual( | ||
obj, | ||
{ a : 1, b : 2, c : [ 3, 4 ] } | ||
)); | ||
var xs = [ 3, 4 ]; | ||
delete xs[1]; | ||
t.ok(deepEqual( | ||
res, { a : 1, c : xs } | ||
)); | ||
t.ok(deepEqual( | ||
res, { a : 1, c : [ 3, ] } | ||
)); | ||
t.ok(deepEqual( | ||
res, { a : 1, c : [ 3 ] } | ||
)); | ||
t.end(); | ||
var obj = { a: 1, b: 2, c: [3, 4] }; | ||
var res = traverse(obj).map(function (x) { | ||
if (this.isLeaf && x % 2 === 0) { this.delete(); } | ||
}); | ||
t.ok(deepEqual( | ||
obj, | ||
{ a: 1, b: 2, c: [3, 4] } | ||
)); | ||
var xs = [3, 4]; | ||
delete xs[1]; | ||
t.ok(deepEqual(res, { a: 1, c: xs })); | ||
t.ok(deepEqual(res, { a: 1, c: [3,,] })); // eslint-disable-line comma-spacing | ||
t.ok(deepEqual(res, { a: 1, c: [3] })); | ||
t.end(); | ||
}); | ||
test('deleteMapRedux', function (t) { | ||
var obj = { a : 1, b : 2, c : [ 3, 4, 5 ] }; | ||
var res = traverse(obj).map(function (x) { | ||
if (this.isLeaf && x % 2 == 0) this.delete(); | ||
}); | ||
t.ok(deepEqual( | ||
obj, | ||
{ a : 1, b : 2, c : [ 3, 4, 5 ] } | ||
)); | ||
var xs = [ 3, 4, 5 ]; | ||
delete xs[1]; | ||
t.ok(deepEqual( | ||
res, { a : 1, c : xs } | ||
)); | ||
t.ok(!deepEqual( | ||
res, { a : 1, c : [ 3, 5 ] } | ||
)); | ||
t.ok(deepEqual( | ||
res, { a : 1, c : [ 3 ,, 5 ] } | ||
)); | ||
t.end(); | ||
var obj = { a: 1, b: 2, c: [3, 4, 5] }; | ||
var res = traverse(obj).map(function (x) { | ||
if (this.isLeaf && x % 2 === 0) { this.delete(); } | ||
}); | ||
t.ok(deepEqual( | ||
obj, | ||
{ a: 1, b: 2, c: [3, 4, 5] } | ||
)); | ||
var xs = [3, 4, 5]; | ||
delete xs[1]; | ||
t.ok(deepEqual(res, { a: 1, c: xs })); | ||
t.ok(!deepEqual(res, { a: 1, c: [3, 5] })); | ||
t.ok(deepEqual(res, { a: 1, c: [3,, 5] })); | ||
t.end(); | ||
}); | ||
test('objectToString', function (t) { | ||
var obj = { a : 1, b : 2, c : [ 3, 4 ] }; | ||
var res = traverse(obj).forEach(function (x) { | ||
if (typeof x === 'object' && !this.isRoot) { | ||
this.update(JSON.stringify(x)); | ||
} | ||
}); | ||
t.same(obj, res); | ||
t.same(obj, { a : 1, b : 2, c : "[3,4]" }); | ||
t.end(); | ||
var obj = { a: 1, b: 2, c: [3, 4] }; | ||
var res = traverse(obj).forEach(function (x) { | ||
if (typeof x === 'object' && !this.isRoot) { | ||
this.update(JSON.stringify(x)); | ||
} | ||
}); | ||
t.same(obj, res); | ||
t.same(obj, { a: 1, b: 2, c: '[3,4]' }); | ||
t.end(); | ||
}); | ||
test('stringToObject', function (t) { | ||
var obj = { a : 1, b : 2, c : "[3,4]" }; | ||
var res = traverse(obj).forEach(function (x) { | ||
if (typeof x === 'string') { | ||
this.update(JSON.parse(x)); | ||
} | ||
else if (typeof x === 'number' && x % 2 === 0) { | ||
this.update(x * 10); | ||
} | ||
}); | ||
t.deepEqual(obj, res); | ||
t.deepEqual(obj, { a : 1, b : 20, c : [ 3, 40 ] }); | ||
t.end(); | ||
var obj = { a: 1, b: 2, c: '[3,4]' }; | ||
var res = traverse(obj).forEach(function (x) { | ||
if (typeof x === 'string') { | ||
this.update(JSON.parse(x)); | ||
} else if (typeof x === 'number' && x % 2 === 0) { | ||
this.update(x * 10); | ||
} | ||
}); | ||
t.deepEqual(obj, res); | ||
t.deepEqual(obj, { a: 1, b: 20, c: [3, 40] }); | ||
t.end(); | ||
}); |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var traverse = require('../'); | ||
@@ -5,18 +7,20 @@ var test = require('tape'); | ||
test('negative update test', function (t) { | ||
var obj = [ 5, 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ]; | ||
var fixed = traverse.map(obj, function (x) { | ||
if (x < 0) this.update(x + 128); | ||
}); | ||
t.same(fixed, | ||
[ 5, 6, 125, [ 7, 8, 126, 1 ], { f: 10, g: 115 } ], | ||
'Negative values += 128' | ||
); | ||
t.same(obj, | ||
[ 5, 6, -3, [ 7, 8, -2, 1 ], { f: 10, g: -13 } ], | ||
'Original references not modified' | ||
); | ||
t.end(); | ||
var obj = [5, 6, -3, [7, 8, -2, 1], { f: 10, g: -13 }]; | ||
var fixed = traverse.map(obj, function (x) { | ||
if (x < 0) { this.update(x + 128); } | ||
}); | ||
t.same( | ||
fixed, | ||
[5, 6, 125, [7, 8, 126, 1], { f: 10, g: 115 }], | ||
'Negative values += 128' | ||
); | ||
t.same( | ||
obj, | ||
[5, 6, -3, [7, 8, -2, 1], { f: 10, g: -13 }], | ||
'Original references not modified' | ||
); | ||
t.end(); | ||
}); |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var test = require('tape'); | ||
@@ -5,8 +7,8 @@ var traverse = require('../'); | ||
test('traverse an object with nested functions', function (t) { | ||
t.plan(1); | ||
function Cons (x) { | ||
t.equal(x, 10) | ||
}; | ||
traverse(new Cons(10)); | ||
t.plan(1); | ||
function Cons(x) { | ||
t.equal(x, 10); | ||
} | ||
traverse(new Cons(10)); | ||
}); |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var test = require('tape'); | ||
@@ -5,34 +7,34 @@ var traverse = require('../'); | ||
test('siblings', function (t) { | ||
var obj = { a : 1, b : 2, c : [ 4, 5, 6 ] }; | ||
var res = traverse(obj).reduce(function (acc, x) { | ||
var p = '/' + this.path.join('/'); | ||
if (this.parent) { | ||
acc[p] = { | ||
siblings : this.parent.keys, | ||
key : this.key, | ||
index : this.parent.keys.indexOf(this.key) | ||
}; | ||
} | ||
else { | ||
acc[p] = { | ||
siblings : [], | ||
key : this.key, | ||
index : -1 | ||
} | ||
} | ||
return acc; | ||
}, {}); | ||
t.same(res, { | ||
'/' : { siblings : [], key : undefined, index : -1 }, | ||
'/a' : { siblings : [ 'a', 'b', 'c' ], key : 'a', index : 0 }, | ||
'/b' : { siblings : [ 'a', 'b', 'c' ], key : 'b', index : 1 }, | ||
'/c' : { siblings : [ 'a', 'b', 'c' ], key : 'c', index : 2 }, | ||
'/c/0' : { siblings : [ '0', '1', '2' ], key : '0', index : 0 }, | ||
'/c/1' : { siblings : [ '0', '1', '2' ], key : '1', index : 1 }, | ||
'/c/2' : { siblings : [ '0', '1', '2' ], key : '2', index : 2 } | ||
}); | ||
t.end(); | ||
var obj = { a: 1, b: 2, c: [4, 5, 6] }; | ||
var res = traverse(obj).reduce(function (acc) { | ||
/* eslint no-param-reassign: 0 */ | ||
var p = '/' + this.path.join('/'); | ||
if (this.parent) { | ||
acc[p] = { | ||
siblings: this.parent.keys, | ||
key: this.key, | ||
index: this.parent.keys.indexOf(this.key), | ||
}; | ||
} else { | ||
acc[p] = { | ||
siblings: [], | ||
key: this.key, | ||
index: -1, | ||
}; | ||
} | ||
return acc; | ||
}, {}); | ||
t.same(res, { | ||
'/': { siblings: [], key: undefined, index: -1 }, | ||
'/a': { siblings: ['a', 'b', 'c'], key: 'a', index: 0 }, | ||
'/b': { siblings: ['a', 'b', 'c'], key: 'b', index: 1 }, | ||
'/c': { siblings: ['a', 'b', 'c'], key: 'c', index: 2 }, | ||
'/c/0': { siblings: ['0', '1', '2'], key: '0', index: 0 }, | ||
'/c/1': { siblings: ['0', '1', '2'], key: '1', index: 1 }, | ||
'/c/2': { siblings: ['0', '1', '2'], key: '2', index: 2 }, | ||
}); | ||
t.end(); | ||
}); |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var test = require('tape'); | ||
@@ -5,41 +7,41 @@ var traverse = require('../'); | ||
test('stop', function (t) { | ||
var visits = 0; | ||
traverse('abcdefghij'.split('')).forEach(function (node) { | ||
if (typeof node === 'string') { | ||
visits ++; | ||
if (node === 'e') this.stop() | ||
} | ||
}); | ||
t.equal(visits, 5); | ||
t.end(); | ||
var visits = 0; | ||
traverse('abcdefghij'.split('')).forEach(function (node) { | ||
if (typeof node === 'string') { | ||
visits += 1; | ||
if (node === 'e') { this.stop(); } | ||
} | ||
}); | ||
t.equal(visits, 5); | ||
t.end(); | ||
}); | ||
test('stopMap', function (t) { | ||
var s = traverse('abcdefghij'.split('')).map(function (node) { | ||
if (typeof node === 'string') { | ||
if (node === 'e') this.stop() | ||
return node.toUpperCase(); | ||
} | ||
}).join(''); | ||
t.equal(s, 'ABCDEfghij'); | ||
t.end(); | ||
var s = traverse('abcdefghij'.split('')).map(function (node) { | ||
if (typeof node === 'string') { | ||
if (node === 'e') { this.stop(); } | ||
return node.toUpperCase(); | ||
} | ||
return void undefined; | ||
}).join(''); | ||
t.equal(s, 'ABCDEfghij'); | ||
t.end(); | ||
}); | ||
test('stopReduce', function (t) { | ||
var obj = { | ||
a : [ 4, 5 ], | ||
b : [ 6, [ 7, 8, 9 ] ] | ||
}; | ||
var xs = traverse(obj).reduce(function (acc, node) { | ||
if (this.isLeaf) { | ||
if (node === 7) this.stop(); | ||
else acc.push(node) | ||
} | ||
return acc; | ||
}, []); | ||
t.same(xs, [ 4, 5, 6 ]); | ||
t.end(); | ||
var obj = { | ||
a: [4, 5], | ||
b: [6, [7, 8, 9]], | ||
}; | ||
var xs = traverse(obj).reduce(function (acc, node) { | ||
if (this.isLeaf) { | ||
if (node === 7) { this.stop(); } else { acc.push(node); } | ||
} | ||
return acc; | ||
}, []); | ||
t.same(xs, [4, 5, 6]); | ||
t.end(); | ||
}); |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var test = require('tape'); | ||
@@ -5,33 +7,30 @@ var traverse = require('../'); | ||
test('stringify', function (t) { | ||
var obj = [ 5, 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ]; | ||
var s = ''; | ||
traverse(obj).forEach(function (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) { | ||
s += '"' + key + '"' + ':'; | ||
}); | ||
this.post(function (child) { | ||
if (!child.isLast) s += ','; | ||
}); | ||
this.after(function () { s += '}' }); | ||
} | ||
else if (typeof node == 'function') { | ||
s += 'null'; | ||
} | ||
else { | ||
s += node.toString(); | ||
} | ||
}); | ||
t.equal(s, JSON.stringify(obj)); | ||
t.end(); | ||
var obj = [5, 6, -3, [7, 8, -2, 1], { f: 10, g: -13 }]; | ||
var s = ''; | ||
traverse(obj).forEach(function (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) { | ||
s += '"' + key + '":'; | ||
}); | ||
this.post(function (child) { | ||
if (!child.isLast) { s += ','; } | ||
}); | ||
this.after(function () { s += '}'; }); | ||
} else if (typeof node === 'function') { | ||
s += 'null'; | ||
} else { | ||
s += node.toString(); | ||
} | ||
}); | ||
t.equal(s, JSON.stringify(obj)); | ||
t.end(); | ||
}); |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var traverse = require('../'); | ||
@@ -5,33 +7,36 @@ var test = require('tape'); | ||
test('subexpr', function (t) { | ||
var obj = [ 'a', 4, 'b', 5, 'c', 6 ]; | ||
var r = traverse(obj).map(function (x) { | ||
if (typeof x === 'number') { | ||
this.update([ x - 0.1, x, x + 0.1 ], true); | ||
} | ||
}); | ||
t.same(obj, [ 'a', 4, 'b', 5, 'c', 6 ]); | ||
t.same(r, [ | ||
'a', [ 3.9, 4, 4.1 ], | ||
'b', [ 4.9, 5, 5.1 ], | ||
'c', [ 5.9, 6, 6.1 ], | ||
]); | ||
t.end(); | ||
var obj = ['a', 4, 'b', 5, 'c', 6]; | ||
var r = traverse(obj).map(function (x) { | ||
if (typeof x === 'number') { | ||
this.update([x - 0.1, x, x + 0.1], true); | ||
} | ||
}); | ||
t.same(obj, ['a', 4, 'b', 5, 'c', 6]); | ||
t.same(r, [ | ||
'a', [3.9, 4, 4.1], | ||
'b', [4.9, 5, 5.1], | ||
'c', [5.9, 6, 6.1], | ||
]); | ||
t.end(); | ||
}); | ||
test('block', function (t) { | ||
var obj = [ [ 1 ], [ 2 ], [ 3 ] ]; | ||
var r = traverse(obj).map(function (x) { | ||
if (Array.isArray(x) && !this.isRoot) { | ||
if (x[0] === 5) this.block() | ||
else this.update([ [ x[0] + 1 ] ]) | ||
} | ||
}); | ||
t.same(r, [ | ||
[ [ [ [ [ 5 ] ] ] ] ], | ||
[ [ [ [ 5 ] ] ] ], | ||
[ [ [ 5 ] ] ], | ||
]); | ||
t.end(); | ||
var obj = [[1], [2], [3]]; | ||
var r = traverse(obj).map(function (x) { | ||
if (Array.isArray(x) && !this.isRoot) { | ||
if (x[0] === 5) { | ||
this.block(); | ||
} else { | ||
this.update([[x[0] + 1]]); | ||
} | ||
} | ||
}); | ||
t.same(r, [ | ||
[[[[[5]]]]], | ||
[[[[5]]]], | ||
[[[5]]], | ||
]); | ||
t.end(); | ||
}); |
@@ -0,56 +1,56 @@ | ||
'use strict'; | ||
var test = require('tape'); | ||
var traverse = require('../'); | ||
var deepEqual = require('./lib/deep_equal'); | ||
function make() { | ||
var a = { self: 'a' }; | ||
var b = { self: 'b' }; | ||
var c = { self: 'c' }; | ||
var d = { self: 'd' }; | ||
var e = { self: 'e' }; | ||
a.a = a; | ||
a.b = b; | ||
a.c = c; | ||
b.a = a; | ||
b.b = b; | ||
b.c = c; | ||
c.a = a; | ||
c.b = b; | ||
c.c = c; | ||
c.d = d; | ||
d.a = a; | ||
d.b = b; | ||
d.c = c; | ||
d.d = d; | ||
d.e = e; | ||
e.a = a; | ||
e.b = b; | ||
e.c = c; | ||
e.d = d; | ||
e.e = e; | ||
return a; | ||
} | ||
test('super_deep', function (t) { | ||
var util = require('util'); | ||
var a0 = make(); | ||
var a1 = make(); | ||
t.ok(deepEqual(a0, a1)); | ||
a0.c.d.moo = true; | ||
t.ok(!deepEqual(a0, a1)); | ||
a1.c.d.moo = true; | ||
t.ok(deepEqual(a0, a1)); | ||
// TODO: this one | ||
//a0.c.a = a1; | ||
//t.ok(!deepEqual(a0, a1)); | ||
t.end(); | ||
var a0 = make(); | ||
var a1 = make(); | ||
t.ok(deepEqual(a0, a1)); | ||
a0.c.d.moo = true; | ||
t.ok(!deepEqual(a0, a1)); | ||
a1.c.d.moo = true; | ||
t.ok(deepEqual(a0, a1)); | ||
// TODO: this one | ||
// a0.c.a = a1; | ||
// t.ok(!deepEqual(a0, a1)); | ||
t.end(); | ||
}); | ||
function make () { | ||
var a = { self : 'a' }; | ||
var b = { self : 'b' }; | ||
var c = { self : 'c' }; | ||
var d = { self : 'd' }; | ||
var e = { self : 'e' }; | ||
a.a = a; | ||
a.b = b; | ||
a.c = c; | ||
b.a = a; | ||
b.b = b; | ||
b.c = c; | ||
c.a = a; | ||
c.b = b; | ||
c.c = c; | ||
c.d = d; | ||
d.a = a; | ||
d.b = b; | ||
d.c = c; | ||
d.d = d; | ||
d.e = e; | ||
e.a = a; | ||
e.b = b; | ||
e.c = c; | ||
e.d = d; | ||
e.e = e; | ||
return a; | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
75941
1
229
8
1336
1