in packages/@aws-cdk/cloudformation-diff/lib/diff/util.ts [19:81]
export function deepEqual(lvalue: any, rvalue: any): boolean {
if (lvalue === rvalue) {
return true;
}
// CloudFormation allows passing strings into boolean-typed fields
if (((typeof lvalue === 'string' && typeof rvalue === 'boolean') ||
(typeof lvalue === 'boolean' && typeof rvalue === 'string')) &&
lvalue.toString() === rvalue.toString()) {
return true;
}
// allows a numeric 10 and a literal "10" to be equivalent;
// this is consistent with CloudFormation.
if ((typeof lvalue === 'string' || typeof rvalue === 'string') &&
safeParseFloat(lvalue) === safeParseFloat(rvalue)) {
return true;
}
if (typeof lvalue !== typeof rvalue) {
return false;
}
if (Array.isArray(lvalue) !== Array.isArray(rvalue)) {
return false;
}
if (Array.isArray(lvalue) /* && Array.isArray(rvalue) */) {
if (lvalue.length !== rvalue.length) {
return false;
}
for (let i = 0 ; i < lvalue.length ; i++) {
if (!deepEqual(lvalue[i], rvalue[i])) {
return false;
}
}
return true;
}
if (typeof lvalue === 'object' /* && typeof rvalue === 'object' */) {
if (lvalue === null || rvalue === null) {
// If both were null, they'd have been ===
return false;
}
const keys = Object.keys(lvalue);
if (keys.length !== Object.keys(rvalue).length) {
return false;
}
for (const key of keys) {
if (!rvalue.hasOwnProperty(key)) {
return false;
}
if (key === 'DependsOn') {
if (!dependsOnEqual(lvalue[key], rvalue[key])) {
return false;
}
// check differences other than `DependsOn`
continue;
}
if (!deepEqual(lvalue[key], rvalue[key])) {
return false;
}
}
return true;
}
// Neither object, nor array: I deduce this is primitive type
// Primitive type and not ===, so I deduce not deepEqual
return false;
}