Last active
August 9, 2024 15:27
-
-
Save netcall-jlo/9f78553b0f6a5894d3c28c3bd638fc8d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// isNonNullObject() | |
console.log('Testing isNonNullObject() ...'); | |
console.assert(isNonNullObject({}), "An Object should be a non-null object"); | |
console.assert(isNonNullObject([]), "An Array should be a non-null object"); | |
console.assert(isNonNullObject(new WeakMap()), "A WeakMap should be a non-null object"); | |
console.assert(!isNonNullObject(null), "null should not be a non-null object"); | |
console.assert(!isNonNullObject(''), "A String should not be a non-null object"); | |
console.log('... complete!'); | |
// isIterable() | |
console.log('Testing isIterable() ...'); | |
console.assert(isIterable([]), "An Array should be iterable"); | |
console.assert(isIterable([0]), "A populated Array should be iterable"); | |
console.assert(isIterable(document.querySelectorAll('body')), "A NodeList should be iterable"); | |
console.assert(isIterable(document.getElementsByTagName('body')), "A live NodeList should be iterable"); | |
console.assert(isIterable(new Set()), "A Set should be iterable"); | |
console.assert(isIterable(new Uint8Array()), "An 8-bit Array should be iterable"); | |
console.assert(isIterable(new Uint16Array()), "A 16-bit Array should be iterable"); | |
console.assert(isIterable(new Uint32Array()), "A 32-bit Array should be iterable"); | |
console.assert(isIterable(new Map()), "A Map should be iterable"); | |
console.assert(!isIterable({}), "An object should not be iterable"); | |
console.assert(!isIterable({ length: 0 }), "A length should not be enough"); | |
console.assert(!isIterable(document.querySelector('body')), "A Node should not be iterable"); | |
console.assert(!isIterable('asd'), "A String should not be iterable"); | |
console.assert(!isIterable(0), "A Number should not be iterable"); | |
console.assert(!isIterable(new WeakMap()), "A WeakMap should not be iterable"); | |
console.log('... complete!'); | |
// keysMatch() | |
console.log('Testing keysMatch() ...'); | |
console.assert(keysMatch([], []), "Empty arrays don't have the same keys"); | |
console.assert(keysMatch([1], [2]), "Arrays don't have the same keys"); | |
console.assert(keysMatch({ a: 1 }, { a: 2 }), "Objects don't have the same keys"); | |
console.assert(keysMatch({ a: 1, b: 2 }, { b: 1, a: 2 }), "Objects with different orders don't have the same keys"); | |
console.assert(keysMatch('012', [0, 1, 2]), "Arrays and Strings don't have the same keys"); | |
console.assert(keysMatch(document.querySelectorAll('body'), document.getElementsByTagName('body')), "NodeLists and live NodeLists don't have the same keys"); | |
console.assert(keysMatch(document.querySelectorAll('body'), [0]), "NodeLists and Arrays don't have the same keys"); | |
console.assert(!keysMatch({ a: 1 }, { a: 1, b: 2 }), "Objects have the same keys as bigger objects"); | |
console.assert(!keysMatch({ a: 1, b: 1 }, { a: 1 }), "Bigger objects have the same keys as smaller ones"); | |
console.log('... complete!'); | |
// looksLike() | |
console.log('Testing looksLike() ...'); | |
// First check: | |
console.assert(looksLike(0, 0), "Numbers don't look the same"); | |
console.assert(looksLike(Number.NaN, Number('a')), "NaN doesn't look like NaN"); | |
console.assert(looksLike(Number.POSITIVE_INFINITY, 1 / 0), "Infinity doesn't look like Infinity"); | |
console.assert(looksLike('asd', 'asd'), "Strings don't look the same"); | |
console.assert(looksLike('0', '0'), "Numeric strings don't look the same"); | |
console.assert(!looksLike(0, 1), "Different numbers look the same"); | |
console.assert(!looksLike('asd', 'qwe'), "Different strings look the same"); | |
console.assert(!looksLike('0', '1'), "Different numeric strings look the same"); | |
console.assert(!looksLike('0', 0), "Numbers and numeric strings look the same"); | |
// Second check: | |
console.assert(looksLike([1], [1]), "Arrays don't look the same"); | |
console.assert(looksLike([[1]], [[1]]), "Nested arrays don't look the same"); | |
console.assert(looksLike([document.body], document.querySelectorAll('body')), "Arrays don't look like array-likes"); | |
console.assert(looksLike(document.getElementsByTagName('body'), document.querySelectorAll('body')), "Array-likess don't look the same"); | |
(() => { const a1 = []; a1[1] = 1; const a2 = []; a2[1] = 1; console.assert(looksLike(a1, a2), "Sparse arrays don't look alike"); })(); | |
console.assert(!looksLike([0], [1]), "Array items don't get checked"); | |
(() => { const a1 = []; a1[1] = 1; const a2 = [0, 1]; console.assert(!looksLike(a1, a2), "Sparse arrays look like dense arrays"); })(); | |
(() => { const a1 = [0, 1]; const a2 = []; a2[1] = 1; console.assert(!looksLike(a1, a2), "Dense arrays look like sparse arrays"); })(); | |
(() => { const a1 = [0, 1, 2]; delete a1[0]; const a2 = [0, 1, 2]; delete a2[1]; console.assert(!looksLike(a1, a2), "Sparse arrays with different games look alike"); })(); | |
console.assert(!looksLike(['0', '1', '2'], '012'), "Arrays and strings look alike"); | |
// Third check: | |
console.assert(looksLike({ a: 1 }, { a: 1 }), "Objects don't look the same"); | |
console.assert(looksLike(window.document, document), "Named objects don't look the same"); | |
console.assert(looksLike({ a: 1, b: 2 }, { b: 2, a: 1 }), "Objects with the same keys in different orders don't look the same"); | |
console.assert(looksLike({ a: [1] }, { a: [1] }), "Nested objects don't look the same"); | |
console.assert(looksLike({ a: { b : 1 } }, { a: { b : 1 } }), "Nested objects don't look the same"); | |
console.assert(looksLike({ a: { b : [1] } }, { a: { b : [1] } }), "Nested objects don't look the same"); | |
console.assert(!looksLike({ a: 1 }, { a: 1, b: 1 }), "Objects looks like larger objects"); | |
console.assert(!looksLike({ a: 1, b: 1 }, { a: 1 }), "Larger objects looks like smaller objects"); | |
console.assert(!looksLike({ a: [0] }, { a: [1] }), "Nested objects aren't checked"); | |
console.assert(!looksLike([], { length: 0 }), "An Array looks like an Object"); | |
console.assert(!looksLike({ length: 0 }, []), "An Object looks like an Array"); | |
console.assert(!looksLike([], ''), "An Array looks like a String"); | |
console.assert(!looksLike('', []), "A String looks like an Array"); | |
console.log('... complete!'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function isNonNullObject(object: unknown): object is Record<PropertyKey, any> { | |
return object !== null && typeof object === 'object'; | |
} | |
function isIterable(source: unknown): source is any[] { | |
return ( | |
isNonNullObject(source) | |
&& typeof (source as any[])[Symbol.iterator] === 'function' | |
); | |
} | |
function keysMatch( | |
source: Record<PropertyKey, any>, | |
check: Record<PropertyKey, any>, | |
) { | |
const sourceKeys = Object.keys(source).sort(); | |
const checkKeys = Object.keys(check).sort(); | |
return ( | |
sourceKeys.length === checkKeys.length | |
&& sourceKeys.every((key, index) => checkKeys[index] === key) | |
); | |
} | |
function looksLike(source: unknown, check: unknown): boolean { | |
// First check: are they the same or do they pass `Object.is()`? | |
if (source === check || Object.is(source, check)) { | |
return true; | |
} | |
// Second check: are they both iterable, have the same length, and contain | |
// the same items in the same order with the same gaps (if any)? | |
if (isIterable(source)) { | |
return ( | |
isIterable(check) | |
&& source.length === check.length | |
&& keysMatch(source, check) | |
&& Array.prototype.every.call( | |
source, | |
(item: any, index: number) => looksLike(item, check[index]), | |
) | |
); | |
} | |
// Third check: are they both objects that contain the same properties and | |
// those properties contain values the look the same? | |
if (isNonNullObject(source)) { | |
return ( | |
isNonNullObject(check) | |
&& keysMatch(source, check) | |
&& Object.entries(source).every(([property, value]) => ( | |
looksLike(value, check[property]) | |
)) | |
); | |
} | |
// Finally: these two items do not look the same. | |
return false; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment