forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1export function choose<U, T extends Record<string, U>>(
2 value: keyof T,
3 choices: T,
4): U {
5 return choices[value]
6}
7
8export function dedupArray<T>(arr: T[]): T[] {
9 const s = new Set(arr)
10 return [...s]
11}
12
13/**
14 * Taken from @tanstack/query-core utils.ts
15 * Modified to support Date object comparisons
16 *
17 * This function returns `a` if `b` is deeply equal.
18 * If not, it will replace any deeply equal children of `b` with those of `a`.
19 * This can be used for structural sharing between JSON values for example.
20 */
21export function replaceEqualDeep(a: any, b: any): any {
22 if (a === b) {
23 return a
24 }
25
26 if (a instanceof Date && b instanceof Date) {
27 return a.getTime() === b.getTime() ? a : b
28 }
29
30 const array = isPlainArray(a) && isPlainArray(b)
31
32 if (array || (isPlainObject(a) && isPlainObject(b))) {
33 const aItems = array ? a : Object.keys(a)
34 const aSize = aItems.length
35 const bItems = array ? b : Object.keys(b)
36 const bSize = bItems.length
37 const copy: any = array ? [] : {}
38
39 let equalItems = 0
40
41 for (let i = 0; i < bSize; i++) {
42 const key = array ? i : bItems[i]
43 if (
44 !array &&
45 a[key] === undefined &&
46 b[key] === undefined &&
47 aItems.includes(key)
48 ) {
49 copy[key] = undefined
50 equalItems++
51 } else {
52 copy[key] = replaceEqualDeep(a[key], b[key])
53 if (copy[key] === a[key] && a[key] !== undefined) {
54 equalItems++
55 }
56 }
57 }
58
59 return aSize === bSize && equalItems === aSize ? a : copy
60 }
61
62 return b
63}
64
65export function isPlainArray(value: unknown) {
66 return Array.isArray(value) && value.length === Object.keys(value).length
67}
68
69// Copied from: https://github.com/jonschlinkert/is-plain-object
70export function isPlainObject(o: any): o is Object {
71 if (!hasObjectPrototype(o)) {
72 return false
73 }
74
75 // If has no constructor
76 const ctor = o.constructor
77 if (ctor === undefined) {
78 return true
79 }
80
81 // If has modified prototype
82 const prot = ctor.prototype
83 if (!hasObjectPrototype(prot)) {
84 return false
85 }
86
87 // If constructor does not have an Object-specific method
88 if (!prot.hasOwnProperty('isPrototypeOf')) {
89 return false
90 }
91
92 // Most likely a plain Object
93 return true
94}
95
96function hasObjectPrototype(o: any): boolean {
97 return Object.prototype.toString.call(o) === '[object Object]'
98}