diff --git a/lib/traverse.js b/lib/traverse.js index 38784bd..94b8688 100644 --- a/lib/traverse.js +++ b/lib/traverse.js @@ -1,16 +1,34 @@ module.exports = Traverse; module.exports.Traverse = Traverse; +var sys = require('sys'); + function Traverse (refObj) { if (!(this instanceof Traverse)) return new Traverse(refObj); // clone refObj for a properly immutable interface: + clone.refs = []; + clone.nodes = []; function clone(ref) { if (typeof ref == 'object' && ref !== null) { var node = ref instanceof Array ? [] : {}; + clone.refs.push(ref); + clone.nodes.push(node); + Object.keys(ref).forEach(function (key) { - node[key] = clone(ref[key]); + var i = clone.refs.indexOf(ref[key]); + if (i >= 0) { + node[key] = clone.nodes[i]; + } + else { + node[key] = clone(ref[key]); + } + }); + + clone.refs.pop(); + clone.nodes.pop(); + // To make instanceof work: node.__proto__ = ref.__proto__; // Probably there are other attributes worth copying @@ -47,9 +65,15 @@ function Traverse (refObj) { state.node = x; }, level : path.length, + circular : null }; + if (typeof node == 'object' && node !== null) { state.isLeaf = Object.keys(node).length == 0 + var circs = parents.filter(function (p) { + return node == p.node + }); + if (circs.length) state.circular = circs[0]; } else { state.isLeaf = true; @@ -59,7 +83,8 @@ function Traverse (refObj) { state.notRoot = !state.isRoot; f.call(state, node); - if (typeof state.node == 'object' && state.node !== null) { + if (typeof state.node == 'object' + && state.node !== null && !state.circular) { parents.push(state); Object.keys(state.node).forEach(function (key) { path.push(key);