deep-compare-by
Version:
Deep compare with a function
71 lines (70 loc) • 2.29 kB
JavaScript
const sNoDefault = Symbol("No default");
const sFailPath = Symbol("Fail path");
const err = msg=>{
throw new Error(msg);
};
const configSymbols = new Set([
sNoDefault,
sFailPath
]);
const cleanTests = tests=>
Array.isArray(tests)
? tests
: tests===null
? []
: typeof tests === "function"
? [tests]
: err("Tests invalid");
const compare = ({ tests, a, b, failPath, noDefault }, path = []) => {
tests = cleanTests(tests);
const testsAdj = noDefault ? tests : [(a, b) => a === b, ...tests];
if (typeof a !== "object" || typeof b !== "object") {
if (testsAdj.some(i => i(a, b))) {
return true;
} else {
return failPath ? path : false;
}
} else if (testsAdj.some(i => i(a, b))) {
return true;
} else if (Object.keys(a)
.length !== Object.keys(b)
.length) {
return failPath ? path : false;
} else if (Object.keys(a)
.length === 0) {
return failPath ? path : false;
} else {
for (const k of Object.keys(a)) {
if (k in b) {
let res;
if ((res = compare({ tests, a:a[k], b:b[k], failPath, noDefault }, path.concat([k]))) !== true) {
return res;
}
} else {
return failPath ? path : false;
}
}
return true;
}
};
const makeCompare = (...args) => {
const properArgs = args.filter(i => !configSymbols.has(i));
if (properArgs.length >= 3) {
const configs = {
tests: properArgs[0],
a: properArgs[1],
b: properArgs[2],
failPath: args.includes(sFailPath),
noDefault: args.includes(sNoDefault),
};
return compare(configs);
} else {
const retFunc = (...newArgs) => makeCompare(...args, ...newArgs);
retFunc.noDefault = (...newArgs) => makeCompare(...args, ...newArgs, sNoDefault);
retFunc.failPath = (...newArgs) => makeCompare(...args, ...newArgs, sFailPath);
retFunc.tests = () => cleanTests(properArgs[0]);
retFunc.lhs = () => properArgs[1];
return retFunc;
}
};
module.exports = makeCompare();