forked from vercel/swr
-
Notifications
You must be signed in to change notification settings - Fork 2
/
hash.ts
70 lines (62 loc) · 2.01 KB
/
hash.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import { OBJECT, isUndefined } from './helper'
// use WeakMap to store the object->key mapping
// so the objects can be garbage collected.
// WeakMap uses a hashtable under the hood, so the lookup
// complexity is almost O(1).
const table = new WeakMap<object, number | string>()
// counter of the key
let counter = 0
// A stable hash implementation that supports:
// - Fast and ensures unique hash properties
// - Handles unserializable values
// - Handles object key ordering
// - Generates short results
//
// This is not a serialization function, and the result is not guaranteed to be
// parsable.
export const stableHash = (arg: any): string => {
const type = typeof arg
const constructor = arg && arg.constructor
const isDate = constructor == Date
let result: any
let index: any
if (OBJECT(arg) === arg && !isDate && constructor != RegExp) {
// Object/function, not null/date/regexp. Use WeakMap to store the id first.
// If it's already hashed, directly return the result.
result = table.get(arg)
if (result) return result
// Store the hash first for circular reference detection before entering the
// recursive `stableHash` calls.
// For other objects like set and map, we use this id directly as the hash.
result = ++counter + '~'
table.set(arg, result)
if (constructor == Array) {
// Array.
result = '@'
for (index = 0; index < arg.length; index++) {
result += stableHash(arg[index]) + ','
}
table.set(arg, result)
}
if (constructor == OBJECT) {
// Object, sort keys.
result = '#'
const keys = OBJECT.keys(arg).sort()
while (!isUndefined((index = keys.pop() as string))) {
if (!isUndefined(arg[index])) {
result += index + ':' + stableHash(arg[index]) + ','
}
}
table.set(arg, result)
}
} else {
result = isDate
? arg.toJSON()
: type == 'symbol'
? arg.toString()
: type == 'string'
? JSON.stringify(arg)
: '' + arg
}
return result
}