Skip to content

Commit

Permalink
fix: deepEqual should respect Date and RegExp, fix koishijs/koishi#1321
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed Dec 26, 2023
1 parent 7e7bcb3 commit 3bed666
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 10 deletions.
19 changes: 10 additions & 9 deletions src/misc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ export function mapValues<U, T, K extends string>(object: Dict<T, K>, transform:

export { mapValues as valueMap }

export function is<K extends keyof typeof globalThis>(type: K, value: any): value is InstanceType<typeof globalThis[K]> {
export function is<K extends keyof typeof globalThis>(type: K): (value: any) => value is InstanceType<typeof globalThis[K]>
export function is<K extends keyof typeof globalThis>(type: K, value: any): value is InstanceType<typeof globalThis[K]>
export function is<K extends keyof typeof globalThis>(type: K, value?: any): any {
if (arguments.length === 1) return (value: any) => is(type, value)
return type in globalThis && value instanceof (globalThis[type] as any)
|| Object.prototype.toString.call(value).slice(8, -1) === type
}
Expand All @@ -49,16 +52,14 @@ export function deepEqual(a: any, b: any, strict?: boolean): boolean {
if (typeof a !== 'object') return false
if (!a || !b) return false

// check array
if (Array.isArray(a)) {
if (!Array.isArray(b) || a.length !== b.length) return false
return a.every((item, index) => deepEqual(item, b[index]))
} else if (Array.isArray(b)) {
return false
function check<T>(test: (x: any) => x is T, then: (a: T, b: T) => boolean) {
return test(a) ? test(b) ? then(a, b) : false : test(b) ? false : undefined
}

// check object
return Object.keys({ ...a, ...b }).every(key => deepEqual(a[key], b[key], strict))
return check(Array.isArray, (a, b) => a.length === b.length && a.every((item, index) => deepEqual(item, b[index])))
?? check(is('Date'), (a, b) => a.valueOf() === b.valueOf())
?? check(is('RegExp'), (a, b) => a.source === b.source && a.flags === b.flags)
?? Object.keys({ ...a, ...b }).every(key => deepEqual(a[key], b[key], strict))
}

export function pick<T extends object, K extends keyof T>(source: T, keys?: Iterable<K>, forced?: boolean) {
Expand Down
16 changes: 15 additions & 1 deletion tests/object.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { expect } from 'chai'
import { defineProperty, pick, omit, clone, mapValues, filterKeys } from '../src'
import { deepEqual, defineProperty, pick, omit, clone, mapValues, filterKeys } from '../src'

describe('Object Manipulations', () => {
it('defineProperty', () => {
Expand Down Expand Up @@ -27,4 +27,18 @@ describe('Object Manipulations', () => {
it('filterKeys', () => {
expect(filterKeys({ a: 1, b: 2 }, k => k === 'a')).to.deep.equal({ a: 1 })
})

it('deepEqual', () => {
expect(deepEqual({ a: 1, b: [2] }, { a: 1, b: [2] })).to.be.true
expect(deepEqual({ a: 1, b: [2] }, { a: 1, b: [3] })).to.be.false

// date
expect(deepEqual(new Date(0), new Date(0))).to.be.true
expect(deepEqual(new Date(0), new Date(1))).to.be.false

// regexp
expect(deepEqual(/a/, /a/)).to.be.true
expect(deepEqual(/a/, /a/i)).to.be.false
expect(deepEqual(/a/, /b/)).to.be.false
})
})

0 comments on commit 3bed666

Please sign in to comment.