Profile editing: Custom fields (deleting, editing) (#38066)
This commit is contained in:
20 files changed
+741
-239
No files matched your search
@@ -0,0 +1,48 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { cyrb32, hashObjectArray } from './hash';
|
||||
|
||||
describe('cyrb32', () => {
|
||||
const input = 'mastodon';
|
||||
|
||||
it('returns a base-36 lowercase 1-6 character string', () => {
|
||||
const hash = cyrb32(input);
|
||||
expect(hash).toMatch(/^[0-9a-z]{1,6}$/);
|
||||
});
|
||||
|
||||
it('returns the same output for same input and seed', () => {
|
||||
const a = cyrb32(input, 1);
|
||||
const b = cyrb32(input, 1);
|
||||
|
||||
expect(a).toBe(b);
|
||||
});
|
||||
|
||||
it('produces different hashes for different seeds', () => {
|
||||
const a = cyrb32(input, 1);
|
||||
const b = cyrb32(input, 2);
|
||||
|
||||
expect(a).not.toBe(b);
|
||||
});
|
||||
});
|
||||
|
||||
describe('hashObjectArray', () => {
|
||||
const input = [
|
||||
{ name: 'Alice', value: 'Developer' },
|
||||
{ name: 'Bob', value: 'Designer' },
|
||||
{ name: 'Alice', value: 'Developer' }, // Duplicate
|
||||
];
|
||||
|
||||
it('returns an array of the same length with unique hash keys', () => {
|
||||
const result = hashObjectArray(input);
|
||||
expect(result).toHaveLength(input.length);
|
||||
|
||||
const ids = result.map((obj) => obj.id);
|
||||
const uniqueIds = new Set(ids);
|
||||
expect(uniqueIds.size).toBe(ids.length);
|
||||
});
|
||||
|
||||
it('allows custom key names for the hash', () => {
|
||||
const result = hashObjectArray(input, 'hashKey');
|
||||
expect(result[0]).toHaveProperty('hashKey');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Fast insecure hash function.
|
||||
* @param str String to hash.
|
||||
* @param seed Optional seed value for different hash outputs of the same string.
|
||||
* @returns Base-36 hash (1-6 characters, typically 5-6).
|
||||
*/
|
||||
export function cyrb32(str: string, seed = 0) {
|
||||
let h1 = 0xdeadbeef ^ seed;
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
h1 = Math.imul(h1 ^ str.charCodeAt(i), 0x9e3779b1);
|
||||
}
|
||||
return ((h1 ^ (h1 >>> 16)) >>> 0).toString(36);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hashes an array of objects into a new array where each object has a unique hash key.
|
||||
* @param array Array of objects to hash.
|
||||
* @param key Key name to use for the hash in the resulting objects (default: 'id').
|
||||
*/
|
||||
export function hashObjectArray<
|
||||
TObj extends object,
|
||||
TKey extends string = 'id',
|
||||
>(array: TObj[], key = 'id' as TKey): (TObj & Record<TKey, string>)[] {
|
||||
const keySet = new Set<string>();
|
||||
|
||||
return array.map((obj) => {
|
||||
const json = JSON.stringify(obj);
|
||||
let seed = 0;
|
||||
let hash = cyrb32(json, seed);
|
||||
while (keySet.has(hash)) {
|
||||
hash = cyrb32(json, ++seed);
|
||||
}
|
||||
keySet.add(hash);
|
||||
return {
|
||||
...obj,
|
||||
[key]: hash,
|
||||
} as TObj & Record<TKey, string>;
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user