mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2024-09-20 07:16:17 +08:00
parent
955eeae2a7
commit
70842599a9
|
@ -1,4 +1,4 @@
|
|||
import { isObject } from "../../src/ts/utils/misc";
|
||||
import { deepClone, isObject } from "../../src/ts/utils/misc";
|
||||
import {
|
||||
getLanguageDisplayString,
|
||||
removeLanguageSize,
|
||||
|
@ -118,4 +118,55 @@ describe("misc.ts", () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
describe("deepClone", () => {
|
||||
it("should correctly clone objects", () => {
|
||||
const tests = [
|
||||
{
|
||||
input: {},
|
||||
expected: {},
|
||||
},
|
||||
{
|
||||
input: { a: 1 },
|
||||
expected: { a: 1 },
|
||||
},
|
||||
{
|
||||
input: { a: { b: 2 } },
|
||||
expected: { a: { b: 2 } },
|
||||
},
|
||||
{
|
||||
input: { a: { b: 2 }, c: [1, 2, 3] },
|
||||
expected: { a: { b: 2 }, c: [1, 2, 3] },
|
||||
},
|
||||
{
|
||||
input: [],
|
||||
expected: [],
|
||||
},
|
||||
{
|
||||
input: [1, 2, 3],
|
||||
expected: [1, 2, 3],
|
||||
},
|
||||
{
|
||||
input: "string",
|
||||
expected: "string",
|
||||
},
|
||||
{
|
||||
input: 1,
|
||||
expected: 1,
|
||||
},
|
||||
{
|
||||
input: null,
|
||||
expected: null,
|
||||
},
|
||||
{
|
||||
input: undefined,
|
||||
expected: undefined,
|
||||
},
|
||||
];
|
||||
|
||||
tests.forEach((test) => {
|
||||
const result = deepClone(test.input);
|
||||
expect(result).toStrictEqual(test.expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2,6 +2,7 @@ import {
|
|||
Config,
|
||||
CustomThemeColors,
|
||||
} from "@monkeytype/contracts/schemas/configs";
|
||||
import { deepClone } from "../utils/misc";
|
||||
|
||||
const obj = {
|
||||
theme: "serika_dark",
|
||||
|
@ -102,4 +103,4 @@ const obj = {
|
|||
maxLineWidth: 0,
|
||||
} as Config;
|
||||
|
||||
export default JSON.parse(JSON.stringify(obj)) as Config;
|
||||
export default deepClone(obj);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { ResultFilters } from "@monkeytype/contracts/schemas/users";
|
||||
import { deepClone } from "../utils/misc";
|
||||
|
||||
const object: ResultFilters = {
|
||||
_id: "default",
|
||||
|
@ -63,4 +64,4 @@ const object: ResultFilters = {
|
|||
},
|
||||
};
|
||||
|
||||
export default JSON.parse(JSON.stringify(object)) as ResultFilters;
|
||||
export default deepClone(object);
|
||||
|
|
|
@ -166,16 +166,12 @@ export async function setFilterPreset(id: string): Promise<void> {
|
|||
).addClass("active");
|
||||
}
|
||||
|
||||
function deepCopyFilter(filter: ResultFilters): ResultFilters {
|
||||
return JSON.parse(JSON.stringify(filter)) as ResultFilters;
|
||||
}
|
||||
|
||||
function addFilterPresetToSnapshot(filter: ResultFilters): void {
|
||||
const snapshot = DB.getSnapshot();
|
||||
if (!snapshot) return;
|
||||
DB.setSnapshot({
|
||||
...snapshot,
|
||||
filterPresets: [...snapshot.filterPresets, deepCopyFilter(filter)],
|
||||
filterPresets: [...snapshot.filterPresets, Misc.deepClone(filter)],
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -963,7 +959,7 @@ $(".group.presetFilterButtons .filterBtns").on(
|
|||
);
|
||||
|
||||
function verifyResultFiltersStructure(filterIn: ResultFilters): ResultFilters {
|
||||
const filter = deepCopyFilter(filterIn);
|
||||
const filter = Misc.deepClone(filterIn);
|
||||
Object.entries(defaultResultFilters).forEach((entry) => {
|
||||
const key = entry[0] as ResultFiltersGroup;
|
||||
const value = entry[1];
|
||||
|
|
|
@ -839,7 +839,7 @@ export async function update(
|
|||
dontSave: boolean
|
||||
): Promise<void> {
|
||||
resultAnnotation = [];
|
||||
result = Object.assign({}, res);
|
||||
result = Misc.deepClone(res);
|
||||
hideCrown();
|
||||
$("#resultWordsHistory .words").empty();
|
||||
$("#result #resultWordsHistory").addClass("hidden");
|
||||
|
|
|
@ -74,7 +74,7 @@ export function clearNotSignedInResult(): void {
|
|||
notSignedInLastResult = null;
|
||||
}
|
||||
|
||||
export function setNotSignedInUid(uid: string): void {
|
||||
export function setNotSignedInUidAndHash(uid: string): void {
|
||||
if (notSignedInLastResult === null) return;
|
||||
notSignedInLastResult.uid = uid;
|
||||
//@ts-expect-error
|
||||
|
@ -897,7 +897,7 @@ export async function finish(difficultyFailed = false): Promise<void> {
|
|||
dontSave = true;
|
||||
}
|
||||
|
||||
const completedEvent = JSON.parse(JSON.stringify(ce)) as CompletedEvent;
|
||||
const completedEvent = Misc.deepClone(ce) as CompletedEvent;
|
||||
|
||||
///////// completed event ready
|
||||
|
||||
|
@ -1054,9 +1054,7 @@ export async function finish(difficultyFailed = false): Promise<void> {
|
|||
|
||||
$("#result .stats .dailyLeaderboard").addClass("hidden");
|
||||
|
||||
TestStats.setLastResult(
|
||||
JSON.parse(JSON.stringify(completedEvent)) as CompletedEvent
|
||||
);
|
||||
TestStats.setLastResult(Misc.deepClone(completedEvent));
|
||||
|
||||
if (!ConnectionState.get()) {
|
||||
ConnectionState.showOfflineBanner();
|
||||
|
|
|
@ -705,4 +705,30 @@ export function parseJsonWithSchema<T>(input: string, schema: ZodSchema<T>): T {
|
|||
}
|
||||
}
|
||||
|
||||
export function deepClone<T>(obj: T[]): T[];
|
||||
export function deepClone<T extends object>(obj: T): T;
|
||||
export function deepClone<T>(obj: T): T;
|
||||
export function deepClone<T>(obj: T | T[]): T | T[] {
|
||||
// Check if the value is a primitive (not an object or array)
|
||||
if (obj === null || typeof obj !== "object") {
|
||||
return obj;
|
||||
}
|
||||
|
||||
// Handle arrays
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map((item) => deepClone(item));
|
||||
}
|
||||
|
||||
// Handle objects
|
||||
const clonedObj = {} as { [K in keyof T]: T[K] };
|
||||
|
||||
for (const key in obj) {
|
||||
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
||||
clonedObj[key] = deepClone((obj as { [K in keyof T]: T[K] })[key]);
|
||||
}
|
||||
}
|
||||
|
||||
return clonedObj;
|
||||
}
|
||||
|
||||
// DO NOT ALTER GLOBAL OBJECTSONSTRUCTOR, IT WILL BREAK RESULT HASHES
|
||||
|
|
|
@ -6,7 +6,7 @@ import * as TestLogic from "../test/test-logic";
|
|||
export async function syncNotSignedInLastResult(uid: string): Promise<void> {
|
||||
const notSignedInLastResult = TestLogic.notSignedInLastResult;
|
||||
if (notSignedInLastResult === null) return;
|
||||
TestLogic.setNotSignedInUid(uid);
|
||||
TestLogic.setNotSignedInUidAndHash(uid);
|
||||
|
||||
const response = await Ape.results.add({
|
||||
body: { result: notSignedInLastResult },
|
||||
|
|
Loading…
Reference in a new issue