-
-
Notifications
You must be signed in to change notification settings - Fork 113
feat(core): add evaluate util #313
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
harry-whorlow
wants to merge
19
commits into
TanStack:main
Choose a base branch
from
harry-whorlow:evaluate
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 1 commit
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
6f26046
feat(core): add evaluate util
harry-whorlow 5c9612a
chore: pr comment
harry-whorlow b436a80
ci: apply automated fixes and generate docs
autofix-ci[bot] 31a570c
chore: protect against mixed inputs
harry-whorlow 0fe9052
ci: apply automated fixes and generate docs
autofix-ci[bot] 50628e1
chore: split mode
harry-whorlow 194eab9
fix: circular references
harry-whorlow 2c9d221
ci: apply automated fixes and generate docs
autofix-ci[bot] a5d59a1
fix: symbol keys eval
harry-whorlow 14efb5e
fix: unstub cleanup
harry-whorlow 4c5120f
chore: update tests
harry-whorlow 06f8762
ci: apply automated fixes and generate docs
autofix-ci[bot] 6352e9c
fix: file test
harry-whorlow ee3609e
ci: apply automated fixes and generate docs
autofix-ci[bot] fe24280
chore: rename
harry-whorlow 913bf8e
fix: subclass instances
harry-whorlow 71b2aa0
ci: apply automated fixes and generate docs
autofix-ci[bot] f788666
Merge branch 'main' into evaluate
KevinVandy 29d88b6
Merge remote-tracking branch 'origin/main' into evaluate
harry-whorlow File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or 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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| export function evaluate<T>(objA: T, objB: T) { | ||
| if (Object.is(objA, objB)) { | ||
| return true | ||
| } | ||
|
|
||
| if ( | ||
| typeof objA !== 'object' || | ||
| objA === null || | ||
| typeof objB !== 'object' || | ||
| objB === null | ||
| ) { | ||
| return false | ||
| } | ||
|
|
||
| if (objA instanceof Date && objB instanceof Date) { | ||
| return objA.getTime() === objB.getTime() | ||
| } | ||
|
|
||
| if (objA instanceof File && objB instanceof File) { | ||
| return ( | ||
| objA.name === objB.name && | ||
| objA.size === objB.size && | ||
| objA.type === objB.type && | ||
| objA.lastModified === objB.lastModified | ||
| ) | ||
| } | ||
|
|
||
| if (objA instanceof Map && objB instanceof Map) { | ||
| if (objA.size !== objB.size) return false | ||
| for (const [k, v] of objA) { | ||
| if (!objB.has(k) || !Object.is(v, objB.get(k))) return false | ||
| } | ||
| return true | ||
| } | ||
|
|
||
| if (objA instanceof Set && objB instanceof Set) { | ||
| if (objA.size !== objB.size) return false | ||
| for (const v of objA) { | ||
| if (!objB.has(v)) return false | ||
| } | ||
| return true | ||
| } | ||
|
|
||
| const keysA = Object.keys(objA as object) | ||
| const keysB = Object.keys(objB as object) | ||
|
|
||
| if (keysA.length !== keysB.length) { | ||
| return false | ||
| } | ||
|
|
||
| for (const key of keysA) { | ||
| if ( | ||
| !keysB.includes(key) || | ||
| !evaluate(objA[key as keyof T], objB[key as keyof T]) | ||
| ) { | ||
| return false | ||
| } | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
|
|
||
| return true | ||
| } | ||
This file contains hidden or 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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,172 @@ | ||
| import { describe, expect, it } from 'vitest' | ||
| import { evaluate } from '../src/evaluate' | ||
|
|
||
| describe('evaluate', () => { | ||
| it('should test equality between primitives', () => { | ||
| const numbersTrue = evaluate(1, 1) | ||
| expect(numbersTrue).toEqual(true) | ||
|
|
||
| const stringFalse = evaluate('uh oh', '') | ||
| expect(stringFalse).toEqual(false) | ||
|
|
||
| const boolTrue = evaluate(true, true) | ||
| expect(boolTrue).toEqual(true) | ||
|
|
||
| const nullFalse = evaluate(null, {}) | ||
| expect(nullFalse).toEqual(false) | ||
|
|
||
| const undefinedFalse = evaluate(undefined, null) | ||
| expect(undefinedFalse).toEqual(false) | ||
| }) | ||
|
|
||
| it('should test equality between arrays', () => { | ||
| const arrayTrue = evaluate([], []) | ||
| expect(arrayTrue).toEqual(true) | ||
|
|
||
| const arrayDeepSearchTrue = evaluate([[1]], [[1]]) | ||
| expect(arrayDeepSearchTrue).toEqual(true) | ||
|
|
||
| const arrayFalse = evaluate([], ['']) | ||
| expect(arrayFalse).toEqual(false) | ||
|
|
||
| const arrayDeepFalse = evaluate([[1]], []) | ||
| expect(arrayDeepFalse).toEqual(false) | ||
|
|
||
| const arrayComplexFalse = evaluate([[{ test: 'true' }], null], [[1], {}]) | ||
| expect(arrayComplexFalse).toEqual(false) | ||
|
|
||
| const arrayComplexTrue = evaluate( | ||
| [[{ test: 'true' }], null], | ||
| [[{ test: 'true' }], null], | ||
| ) | ||
| expect(arrayComplexTrue).toEqual(true) | ||
| }) | ||
|
|
||
| it('should test equality between objects', () => { | ||
| const objTrue = evaluate({ test: 'same' }, { test: 'same' }) | ||
| expect(objTrue).toEqual(true) | ||
|
|
||
| const objFalse = evaluate({ test: 'not' }, { test: 'same' }) | ||
| expect(objFalse).toEqual(false) | ||
|
|
||
| const objDeepFalse = evaluate({ test: 'not' }, { test: { test: 'same' } }) | ||
| expect(objDeepFalse).toEqual(false) | ||
|
|
||
| const objDeepArrFalse = evaluate({ test: [] }, { test: [[]] }) | ||
| expect(objDeepArrFalse).toEqual(false) | ||
|
|
||
| const objNullFalse = evaluate({ test: '' }, null) | ||
| expect(objNullFalse).toEqual(false) | ||
|
|
||
| const objComplexFalse = evaluate( | ||
| { test: { testTwo: '' }, arr: [[1]] }, | ||
| { test: { testTwo: false }, arr: [[1], [0]] }, | ||
| ) | ||
| expect(objComplexFalse).toEqual(false) | ||
|
|
||
| const objComplexTrue = evaluate( | ||
| { test: { testTwo: '' }, arr: [[1]] }, | ||
| { test: { testTwo: '' }, arr: [[1]] }, | ||
| ) | ||
| expect(objComplexTrue).toEqual(true) | ||
| }) | ||
|
|
||
| it('should test equality between Date objects', () => { | ||
| const date1 = new Date('2025-01-01T00:00:00.000Z') | ||
| const date2 = new Date('2025-01-01T00:00:00.000Z') | ||
| const date3 = new Date('2025-01-02T00:00:00.000Z') | ||
|
|
||
| const dateTrue = evaluate(date1, date2) | ||
| expect(dateTrue).toEqual(true) | ||
|
|
||
| const dateFalse = evaluate(date1, date3) | ||
| expect(dateFalse).toEqual(false) | ||
|
|
||
| const dateObjectTrue = evaluate({ date: date1 }, { date: date2 }) | ||
| expect(dateObjectTrue).toEqual(true) | ||
|
|
||
| const dateObjectFalse = evaluate({ date: date1 }, { date: date3 }) | ||
| expect(dateObjectFalse).toEqual(false) | ||
| }) | ||
|
|
||
| it('should test equality between Map objects', () => { | ||
| const map1 = new Map([ | ||
| ['a', 1], | ||
| ['b', 2], | ||
| ]) | ||
| const map2 = new Map([ | ||
| ['a', 1], | ||
| ['b', 2], | ||
| ]) | ||
| expect(evaluate(map1, map2)).toEqual(true) | ||
|
|
||
| const emptyMap1 = new Map() | ||
| const emptyMap2 = new Map() | ||
| expect(evaluate(emptyMap1, emptyMap2)).toEqual(true) | ||
|
|
||
| const mapSmall = new Map([['a', 1]]) | ||
| const mapLarge = new Map([ | ||
| ['a', 1], | ||
| ['b', 2], | ||
| ]) | ||
| expect(evaluate(mapSmall, mapLarge)).toEqual(false) | ||
|
|
||
| const mapA = new Map([ | ||
| ['a', 1], | ||
| ['b', 2], | ||
| ]) | ||
| const mapC = new Map([ | ||
| ['a', 1], | ||
| ['c', 2], | ||
| ]) | ||
| expect(evaluate(mapA, mapC)).toEqual(false) | ||
|
|
||
| const mapVal1 = new Map([ | ||
| ['a', 1], | ||
| ['b', 2], | ||
| ]) | ||
| const mapVal2 = new Map([ | ||
| ['a', 1], | ||
| ['b', 3], | ||
| ]) | ||
| expect(evaluate(mapVal1, mapVal2)).toEqual(false) | ||
| }) | ||
|
|
||
| it('should test equality between Set objects', () => { | ||
| const set1 = new Set([1, 2, 3]) | ||
| const set2 = new Set([1, 2, 3]) | ||
| expect(evaluate(set1, set2)).toEqual(true) | ||
|
|
||
| const emptySet1 = new Set() | ||
| const emptySet2 = new Set() | ||
| expect(evaluate(emptySet1, emptySet2)).toEqual(true) | ||
|
|
||
| const setSmall = new Set([1, 2]) | ||
| const setLarge = new Set([1, 2, 3]) | ||
| expect(evaluate(setSmall, setLarge)).toEqual(false) | ||
|
|
||
| const setA = new Set([1, 2, 3]) | ||
| const setB = new Set([1, 2, 4]) | ||
| expect(evaluate(setA, setB)).toEqual(false) | ||
| }) | ||
|
|
||
| it('should test equality between File objects', () => { | ||
| const file1 = new File(['hello'], 'hello.txt', { type: 'text/plain' }) | ||
| const file2 = new File(['hello'], 'hello.txt', { type: 'text/plain' }) | ||
| const fileDiffName = new File(['hello'], 'world.txt', { | ||
| type: 'text/plain', | ||
| }) | ||
| const fileDiffType = new File(['hello'], 'hello.txt', { type: 'text/html' }) | ||
| const fileDiffSize = new File(['hello world'], 'hello.txt', { | ||
| type: 'text/plain', | ||
| }) | ||
|
|
||
| expect(evaluate(file1, file2)).toEqual(true) | ||
| expect(evaluate(file1, fileDiffName)).toEqual(false) | ||
| expect(evaluate(file1, fileDiffType)).toEqual(false) | ||
| expect(evaluate(file1, fileDiffSize)).toEqual(false) | ||
|
|
||
| expect(evaluate({ file: file1 }, { file: file2 })).toEqual(true) | ||
| expect(evaluate({ file: file1 }, { file: fileDiffName })).toEqual(false) | ||
| }) | ||
| }) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.