json-deep-compare
Version:
A powerful library for comparing JSON objects with support for deep comparison, regex validation, and customizable options
1 lines • 2.83 kB
JavaScript
const PathUtils=require("./PathUtils");class Comparator{constructor(t,e,a){this.options=t,this.result=e,this.regexValidator=a}getValueType(t){if(null===t)return"null";if(Array.isArray(t))return"array";if(t instanceof Date)return"date";if(t instanceof RegExp)return"regex";const e=typeof t;if("object"===e){const e=t.constructor.name.toLowerCase();return"object"!==e?e:"object"}return e}compareObjects(t={},e={},a=""){if(null===t||null===e)return void this.compareValues(t,e,a);if(Array.isArray(t)&&Array.isArray(e))return void this.compareArrays(t,e,a);if("object"!=typeof t||"object"!=typeof e)return void this.compareValues(t,e,a);const s=Object.keys(t).filter((t=>!this.options.ignoredKeys.includes(t)));for(const r of s){const s=PathUtils.buildPath(a,r);r in e?(this.result.addMatchedKey(s),"object"==typeof t[r]&&null!==t[r]&&"object"==typeof e[r]&&null!==e[r]?this.compareObjects(t[r],e[r],s):this.compareValues(t[r],e[r],s)):this.result.addUnmatchedKey({path:s,value:t[r],message:"Key exists in object 1 but not in object 2"})}if(!this.options.ignoreExtraKeys)for(const s of Object.keys(e))if(!this.options.ignoredKeys.includes(s)&&!(s in t)){const t=PathUtils.buildPath(a,s);this.result.addUnmatchedKey({path:t,value:e[s],message:"Key exists in object 2 but not in object 1"})}}compareArrays(t,e,a){t.length!==e.length&&this.result.addUnmatchedValue({path:a,expected:`Array of length ${t.length}`,actual:`Array of length ${e.length}`,message:"Array lengths do not match"});const s=Math.min(t.length,e.length);for(let r=0;r<s;r++){const s=PathUtils.buildArrayPath(a,r);"object"==typeof t[r]&&null!==t[r]&&"object"==typeof e[r]&&null!==e[r]?this.compareObjects(t[r],e[r],s):this.compareValues(t[r],e[r],s)}for(let e=s;e<t.length;e++){const s=PathUtils.buildArrayPath(a,e);this.result.addUnmatchedValue({path:s,expected:t[e],actual:void 0,message:"Extra element in first array"})}for(let t=s;t<e.length;t++){const s=PathUtils.buildArrayPath(a,t);this.result.addUnmatchedValue({path:s,expected:void 0,actual:e[t],message:"Extra element in second array"})}}compareValues(t,e,a){const s=this.getValueType(t),r=this.getValueType(e);for(const[o,i]of Object.entries(this.options.equivalentValues))if(Array.isArray(i)&&i.includes(t)&&i.includes(e))return void this.result.addMatchedValue({path:a,value:`${t} ≈ ${e}`,type1:s,type2:r,message:`Values considered equivalent by rule "${o}"`});if(s!==r&&(this.result.addUnmatchedType({path:a,expected:s,actual:r,message:`Types do not match: expected '${s}', got '${r}'`}),this.options.strictTypes))return;let o;o=this.options.strictTypes?t===e:t==e,o?this.result.addMatchedValue({path:a,value:t,type:s}):this.result.addUnmatchedValue({path:a,expected:t,actual:e,expectedType:s,actualType:r,message:"Values do not match"}),this.regexValidator.validateValue(e,a)}}module.exports=Comparator;