|
Mfunction objcopy(obj) { |
|
if (Array.isArray(obj)) { |
|
return obj.slice(0); |
|
} else if (typeof (obj) === "object") { |
|
var newobj = {}; |
|
for (var key in obj) { newobj[key] = objcopy(obj[key]); } |
|
return newobj; |
|
} else { |
|
return obj; |
|
} |
|
} |
|
|
|
function getSubObj (obj, key) { |
|
var tmpobj = obj; |
|
for (var i=0; i<key.length; i++) { |
|
if (typeof (tmpobj[key[i]]) === "object" || i===key.length-1) { |
|
tmpobj = tmpobj[key[i]]; |
|
} else { |
|
throw new Error("Invalid key"); |
|
} |
|
} |
|
return tmpobj; |
|
} |
|
|
|
function deleteKey (obj, key) { |
|
var subobj = getSubObj(obj, key.slice(0,-1)); |
|
var ret = subobj[key[key.length-1]]; |
|
delete subobj[key[key.length-1]]; |
|
return ret; |
|
} |
|
|
|
function insertKey (obj, key, value) { |
|
var tmp = obj; |
|
for (var i=0; i<key.length-1; i++) { |
|
if (typeof (tmp[key[i]]) !== "object"){ |
|
tmp[key[i]] = {}; |
|
} |
|
tmp = tmp[key[i]]; |
|
} |
|
tmp[key[i]] = value; |
|
return obj; |
|
} |
|
|
|
function firstKey (obj) { |
|
if (typeof (obj) === "object") { |
|
var key = Object.keys(obj).sort()[0]; |
|
if (key === undefined) { |
|
return []; |
|
} else { |
|
return [key].concat(firstKey(obj[key])) |
|
} |
|
} else { |
|
return []; |
|
} |
|
} |
|
|
|
function nextKey (obj, key) { |
|
if (key === undefined) return firstKey(obj); |
|
var subkey = key.slice(); |
|
do { |
|
var lastPartOfKey = subkey.pop(); |
|
//The key was the last key in the object |
|
if (lastPartOfKey === undefined) return null; |
|
var subobj = getSubObj(obj, subkey); |
|
var keys = Object.keys(subobj).sort(); |
|
var index = keys.indexOf(lastPartOfKey); |
|
if (index === -1) throw new Error("Invalid key"); |
|
} while (index === keys.length-1); |
|
return subkey.concat(keys[index+1], firstKey(subobj[keys[index+1]])); |
|
} |
|
|
|
function reduceInput(input, testfunc, testFinishedCallback) { |
|
var key, ret=objcopy(input), waitingCallbacks=0, finished=false; |
|
while (1) { |
|
var key = nextKey(input, key); |
|
if (key === null) break; |
|
var removed = deleteKey(input, key); |
|
(function(){ |
|
var thisKey = key; |
|
try { |
|
waitingCallbacks++; |
|
var testresult = testfunc(input, function(testpassed){ |
|
//If the test still passes even without the key, we can remove it |
|
if (testpassed) { |
|
deleteKey(ret, thisKey); |
|
} |
|
waitingCallbacks--; |
|
if (waitingCallbacks===0 && finished===true) { |
|
testFinishedCallback(ret); |
|
} |
|
}); |
|
} catch (e) {} |
|
})(); |
|
insertKey(input, key, removed); |
|
} |
|
finished = true; |
|
if (waitingCallbacks===0) { |
|
testFinishedCallback (ret); |
|
} |
|
} |
|
|
|
/* |
|
//Exemple : |
|
var obj={a:{b:[1,2]},c:[0]}; |
|
reduceInput( |
|
obj, |
|
function(red, callb){ |
|
var ret = typeof(red.a.b[0])==="number"; |
|
console.log(red, ret); |
|
callb(ret); |
|
}, |
|
function(reduced){ |
|
console.log("obj",obj,"reduced",reduced); |
|
} |
|
); |
|
*/ |
|
|
|
if (exports) { |
|
exports.reduceInput = reduceInput; |
|
exports.nextKey = nextKey; |
|
} |