From 797647c74cfe3a6798f37f5182f1682a71e13ca8 Mon Sep 17 00:00:00 2001 From: Mohit Paddhariya Date: Thu, 23 Jan 2025 14:14:28 +0530 Subject: [PATCH 1/4] refactor(parsing): Replace JSON.parse with parseJsonWithSchema (@dev-mohit06) --- frontend/src/ts/commandline/lists.ts | 6 ++-- .../ts/controllers/analytics-controller.ts | 17 ++++++++- frontend/src/ts/event-handlers/account.ts | 6 +++- .../src/ts/modals/import-export-settings.ts | 6 ++-- frontend/src/ts/test/custom-text.ts | 7 ++++ frontend/src/ts/test/wikipedia.ts | 28 +++++++++++++-- .../src/ts/utils/local-storage-with-schema.ts | 3 +- frontend/src/ts/utils/url-handler.ts | 36 ++++++++++++++++--- 8 files changed, 95 insertions(+), 14 deletions(-) diff --git a/frontend/src/ts/commandline/lists.ts b/frontend/src/ts/commandline/lists.ts index 100032beff17..d6965c3f5616 100644 --- a/frontend/src/ts/commandline/lists.ts +++ b/frontend/src/ts/commandline/lists.ts @@ -108,6 +108,7 @@ import * as FPSCounter from "../elements/fps-counter"; import { migrateConfig } from "../utils/config"; import { PartialConfigSchema } from "@monkeytype/contracts/schemas/configs"; import { Command, CommandsSubgroup } from "./types"; +import { parseWithSchema as parseJsonWithSchema } from "@monkeytype/util/json"; const layoutsPromise = JSONData.getLayoutsList(); layoutsPromise @@ -362,8 +363,9 @@ export const commands: CommandsSubgroup = { exec: async ({ input }): Promise => { if (input === undefined || input === "") return; try { - const parsedConfig = PartialConfigSchema.strip().parse( - JSON.parse(input) + const parsedConfig = parseJsonWithSchema( + input, + PartialConfigSchema.strip() ); await UpdateConfig.apply(migrateConfig(parsedConfig)); UpdateConfig.saveFullConfigToLocalStorage(); diff --git a/frontend/src/ts/controllers/analytics-controller.ts b/frontend/src/ts/controllers/analytics-controller.ts index 56fbc7eaf086..8fe508bdf6e6 100644 --- a/frontend/src/ts/controllers/analytics-controller.ts +++ b/frontend/src/ts/controllers/analytics-controller.ts @@ -6,6 +6,8 @@ import { } from "firebase/analytics"; import { app as firebaseApp } from "../firebase"; import { createErrorMessage } from "../utils/misc"; +import { parseWithSchema as parseJsonWithSchema } from "@monkeytype/util/json"; +import { z } from "zod"; let analytics: AnalyticsType; @@ -14,6 +16,11 @@ type AcceptedCookies = { analytics: boolean; }; +const acceptedCookiesSchema = z.object({ + security: z.boolean(), + analytics: z.boolean(), +}); + export async function log( eventName: string, params?: Record @@ -28,7 +35,15 @@ export async function log( const lsString = localStorage.getItem("acceptedCookies"); let acceptedCookies; if (lsString !== undefined && lsString !== null && lsString !== "") { - acceptedCookies = JSON.parse(lsString) as AcceptedCookies; + try { + acceptedCookies = parseJsonWithSchema( + lsString, + acceptedCookiesSchema + ) as AcceptedCookies; + } catch (e) { + console.error("Failed to parse accepted cookies:", e); + acceptedCookies = null; + } } else { acceptedCookies = null; } diff --git a/frontend/src/ts/event-handlers/account.ts b/frontend/src/ts/event-handlers/account.ts index af42fdc14a23..dda43f165152 100644 --- a/frontend/src/ts/event-handlers/account.ts +++ b/frontend/src/ts/event-handlers/account.ts @@ -5,6 +5,8 @@ import { isAuthenticated } from "../firebase"; import * as Notifications from "../elements/notifications"; import * as EditResultTagsModal from "../modals/edit-result-tags"; import * as AddFilterPresetModal from "../modals/new-filter-preset"; +import { parseWithSchema as parseJsonWithSchema } from "@monkeytype/util/json"; +import { z } from "zod"; const accountPage = document.querySelector("#pageAccount") as HTMLElement; @@ -39,9 +41,11 @@ $(accountPage).on("click", ".editProfileButton", () => { $(accountPage).on("click", ".group.history .resultEditTagsButton", (e) => { const resultid = $(e.target).attr("data-result-id"); const tags = $(e.target).attr("data-tags"); + const tagsArraySchema = z.array(z.string()); + EditResultTagsModal.show( resultid ?? "", - JSON.parse(tags ?? "[]") as string[], + parseJsonWithSchema(tags ?? "[]", tagsArraySchema), "accountPage" ); }); diff --git a/frontend/src/ts/modals/import-export-settings.ts b/frontend/src/ts/modals/import-export-settings.ts index ff0cb82d4add..1994064dc1ee 100644 --- a/frontend/src/ts/modals/import-export-settings.ts +++ b/frontend/src/ts/modals/import-export-settings.ts @@ -3,6 +3,7 @@ import * as UpdateConfig from "../config"; import * as Notifications from "../elements/notifications"; import AnimatedModal from "../utils/animated-modal"; import { migrateConfig } from "../utils/config"; +import { parseWithSchema as parseJsonWithSchema } from "@monkeytype/util/json"; type State = { mode: "import" | "export"; @@ -47,8 +48,9 @@ const modal = new AnimatedModal({ return; } try { - const parsedConfig = PartialConfigSchema.strip().parse( - JSON.parse(state.value) + const parsedConfig = parseJsonWithSchema( + state.value, + PartialConfigSchema.strip() ); await UpdateConfig.apply(migrateConfig(parsedConfig)); } catch (e) { diff --git a/frontend/src/ts/test/custom-text.ts b/frontend/src/ts/test/custom-text.ts index a0d59cb2ff44..28b81b2c6e04 100644 --- a/frontend/src/ts/test/custom-text.ts +++ b/frontend/src/ts/test/custom-text.ts @@ -66,6 +66,13 @@ const customTextSettings = new LocalStorageWithSchema({ }, }); +export const customTextDataSchema = z.object({ + text: z.array(z.string()), + mode: CustomTextModeSchema, + limit: z.object({ value: z.number(), mode: CustomTextLimitModeSchema }), + pipeDelimiter: z.boolean(), +}); + export function getText(): string[] { return customTextSettings.get().text; } diff --git a/frontend/src/ts/test/wikipedia.ts b/frontend/src/ts/test/wikipedia.ts index 5bed9a7c6749..b7b1dcedecbb 100644 --- a/frontend/src/ts/test/wikipedia.ts +++ b/frontend/src/ts/test/wikipedia.ts @@ -2,6 +2,8 @@ import * as Loader from "../elements/loader"; import * as Misc from "../utils/misc"; import * as Strings from "../utils/strings"; import * as JSONData from "../utils/json-data"; +import { z } from "zod"; +import { parseWithSchema as parseJsonWithSchema } from "@monkeytype/util/json"; export async function getTLD( languageGroup: JSONData.LanguageGroup @@ -285,10 +287,30 @@ export async function getSection(language: string): Promise { sectionReq.onload = (): void => { if (sectionReq.readyState === 4) { if (sectionReq.status === 200) { + // Section Schema + const sectionSchema = z.object({ + query: z.object({ + pages: z.record( + z.string(), + z.object({ + extract: z.string(), + }) + ), + }), + }); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - let sectionText = JSON.parse(sectionReq.responseText).query.pages[ - pageid.toString() - ].extract as string; + const parsedResponse = parseJsonWithSchema( + sectionReq.responseText, + sectionSchema + ); + const page = parsedResponse.query.pages[pageid.toString()]; + if (!page) { + Loader.hide(); + rej("Page not found"); + return; + } + let sectionText = page.extract; // Converting to one paragraph sectionText = sectionText.replace(/<\/p>

+/g, " "); diff --git a/frontend/src/ts/utils/local-storage-with-schema.ts b/frontend/src/ts/utils/local-storage-with-schema.ts index 42c3d593b27e..f344b76b9874 100644 --- a/frontend/src/ts/utils/local-storage-with-schema.ts +++ b/frontend/src/ts/utils/local-storage-with-schema.ts @@ -1,5 +1,6 @@ import { ZodError, ZodIssue } from "zod"; import { deepClone } from "./misc"; +import { parseWithSchema as parseJsonWithSchema } from "@monkeytype/util/json"; export class LocalStorageWithSchema { private key: string; @@ -28,7 +29,7 @@ export class LocalStorageWithSchema { let jsonParsed: unknown; try { - jsonParsed = JSON.parse(value); + jsonParsed = parseJsonWithSchema(value, this.schema); } catch (e) { console.log( `Value from localStorage ${this.key} was not a valid JSON, using fallback`, diff --git a/frontend/src/ts/utils/url-handler.ts b/frontend/src/ts/utils/url-handler.ts index 036e8d4700eb..cb0376e906ca 100644 --- a/frontend/src/ts/utils/url-handler.ts +++ b/frontend/src/ts/utils/url-handler.ts @@ -11,7 +11,13 @@ import * as Loader from "../elements/loader"; import * as AccountButton from "../elements/account-button"; import { restart as restartTest } from "../test/test-logic"; import * as ChallengeController from "../controllers/challenge-controller"; -import { Mode, Mode2 } from "@monkeytype/contracts/schemas/shared"; +import { + DifficultySchema, + Mode, + Mode2, + Mode2Schema, + ModeSchema, +} from "@monkeytype/contracts/schemas/shared"; import { CustomBackgroundFilter, CustomBackgroundFilterSchema, @@ -144,9 +150,31 @@ export function loadTestSettingsFromUrl(getOverride?: string): void { const getValue = Misc.findGetParameter("testSettings", getOverride); if (getValue === null) return; - const de = JSON.parse( - decompressFromURI(getValue) ?? "" - ) as SharedTestSettings; + const testSettingsSchema = z.tuple([ + z.union([ModeSchema, z.null()]), // Mode | null + z.union([Mode2Schema, z.null()]), // Mode2 | null + z.union([CustomText.customTextDataSchema, z.null()]), // CustomTextData | null + z.union([z.boolean(), z.null()]), // boolean | null + z.union([z.boolean(), z.null()]), // boolean | null + z.union([z.string(), z.null()]), // string | null + z.union([DifficultySchema, z.null()]), // Difficulty | null + z.union([z.string(), z.null()]), // string | null + ]); + + let de: SharedTestSettings; + try { + const decompressed = decompressFromURI(getValue) ?? ""; + de = testSettingsSchema.parse( + JSON.parse(decompressed) + ) as SharedTestSettings; + } catch (e) { + console.error("Failed to parse test settings:", e); + Notifications.add( + "Failed to load test settings from URL: " + (e as Error).message, + 0 + ); + return; + } const applied: Record = {}; From 475dac554bfed004718be200fa388906fb78c8b6 Mon Sep 17 00:00:00 2001 From: Mohit Paddhariya Date: Fri, 24 Jan 2025 03:24:28 +0530 Subject: [PATCH 2/4] refactor: update schema definitions and replace JSON.parse with parseWithSchema (@dev-mohit06) - Updated schema definitions for better clarity and reusability. - Replaced with where applicable. - Addressed all review comments for better code consistency. --- .../ts/controllers/analytics-controller.ts | 14 ++---- frontend/src/ts/event-handlers/account.ts | 3 +- frontend/src/ts/test/custom-text.ts | 8 +--- frontend/src/ts/test/wikipedia.ts | 25 +++++----- .../src/ts/utils/local-storage-with-schema.ts | 3 +- frontend/src/ts/utils/url-handler.ts | 47 ++++++++----------- 6 files changed, 41 insertions(+), 59 deletions(-) diff --git a/frontend/src/ts/controllers/analytics-controller.ts b/frontend/src/ts/controllers/analytics-controller.ts index 8fe508bdf6e6..de43400880f7 100644 --- a/frontend/src/ts/controllers/analytics-controller.ts +++ b/frontend/src/ts/controllers/analytics-controller.ts @@ -11,16 +11,13 @@ import { z } from "zod"; let analytics: AnalyticsType; -type AcceptedCookies = { - security: boolean; - analytics: boolean; -}; - const acceptedCookiesSchema = z.object({ security: z.boolean(), analytics: z.boolean(), }); +type AcceptedCookies = z.infer; // Updated type inference + export async function log( eventName: string, params?: Record @@ -33,13 +30,10 @@ export async function log( } const lsString = localStorage.getItem("acceptedCookies"); -let acceptedCookies; +let acceptedCookies: AcceptedCookies | null; if (lsString !== undefined && lsString !== null && lsString !== "") { try { - acceptedCookies = parseJsonWithSchema( - lsString, - acceptedCookiesSchema - ) as AcceptedCookies; + acceptedCookies = parseJsonWithSchema(lsString, acceptedCookiesSchema); } catch (e) { console.error("Failed to parse accepted cookies:", e); acceptedCookies = null; diff --git a/frontend/src/ts/event-handlers/account.ts b/frontend/src/ts/event-handlers/account.ts index dda43f165152..10a41756a794 100644 --- a/frontend/src/ts/event-handlers/account.ts +++ b/frontend/src/ts/event-handlers/account.ts @@ -38,10 +38,11 @@ $(accountPage).on("click", ".editProfileButton", () => { EditProfileModal.show(); }); +const tagsArraySchema = z.array(z.string()); + $(accountPage).on("click", ".group.history .resultEditTagsButton", (e) => { const resultid = $(e.target).attr("data-result-id"); const tags = $(e.target).attr("data-tags"); - const tagsArraySchema = z.array(z.string()); EditResultTagsModal.show( resultid ?? "", diff --git a/frontend/src/ts/test/custom-text.ts b/frontend/src/ts/test/custom-text.ts index 28b81b2c6e04..0e0662d70d07 100644 --- a/frontend/src/ts/test/custom-text.ts +++ b/frontend/src/ts/test/custom-text.ts @@ -66,12 +66,8 @@ const customTextSettings = new LocalStorageWithSchema({ }, }); -export const customTextDataSchema = z.object({ - text: z.array(z.string()), - mode: CustomTextModeSchema, - limit: z.object({ value: z.number(), mode: CustomTextLimitModeSchema }), - pipeDelimiter: z.boolean(), -}); +// reassigned to CustomTextSettingsSchema +export const CustomTextDataSchema = CustomTextSettingsSchema; export function getText(): string[] { return customTextSettings.get().text; diff --git a/frontend/src/ts/test/wikipedia.ts b/frontend/src/ts/test/wikipedia.ts index b7b1dcedecbb..883c50246f1e 100644 --- a/frontend/src/ts/test/wikipedia.ts +++ b/frontend/src/ts/test/wikipedia.ts @@ -243,6 +243,18 @@ type SectionObject = { author: string; }; +// Section Schema +const sectionSchema = z.object({ + query: z.object({ + pages: z.record( + z.string(), + z.object({ + extract: z.string(), + }) + ), + }), +}); + export async function getSection(language: string): Promise { // console.log("Getting section"); Loader.show(); @@ -287,19 +299,6 @@ export async function getSection(language: string): Promise { sectionReq.onload = (): void => { if (sectionReq.readyState === 4) { if (sectionReq.status === 200) { - // Section Schema - const sectionSchema = z.object({ - query: z.object({ - pages: z.record( - z.string(), - z.object({ - extract: z.string(), - }) - ), - }), - }); - - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access const parsedResponse = parseJsonWithSchema( sectionReq.responseText, sectionSchema diff --git a/frontend/src/ts/utils/local-storage-with-schema.ts b/frontend/src/ts/utils/local-storage-with-schema.ts index f344b76b9874..42c3d593b27e 100644 --- a/frontend/src/ts/utils/local-storage-with-schema.ts +++ b/frontend/src/ts/utils/local-storage-with-schema.ts @@ -1,6 +1,5 @@ import { ZodError, ZodIssue } from "zod"; import { deepClone } from "./misc"; -import { parseWithSchema as parseJsonWithSchema } from "@monkeytype/util/json"; export class LocalStorageWithSchema { private key: string; @@ -29,7 +28,7 @@ export class LocalStorageWithSchema { let jsonParsed: unknown; try { - jsonParsed = parseJsonWithSchema(value, this.schema); + jsonParsed = JSON.parse(value); } catch (e) { console.log( `Value from localStorage ${this.key} was not a valid JSON, using fallback`, diff --git a/frontend/src/ts/utils/url-handler.ts b/frontend/src/ts/utils/url-handler.ts index cb0376e906ca..b737c7d7f018 100644 --- a/frontend/src/ts/utils/url-handler.ts +++ b/frontend/src/ts/utils/url-handler.ts @@ -13,8 +13,6 @@ import { restart as restartTest } from "../test/test-logic"; import * as ChallengeController from "../controllers/challenge-controller"; import { DifficultySchema, - Mode, - Mode2, Mode2Schema, ModeSchema, } from "@monkeytype/contracts/schemas/shared"; @@ -25,7 +23,6 @@ import { CustomBackgroundSizeSchema, CustomThemeColors, CustomThemeColorsSchema, - Difficulty, } from "@monkeytype/contracts/schemas/configs"; import { z } from "zod"; import { parseWithSchema as parseJsonWithSchema } from "@monkeytype/util/json"; @@ -135,38 +132,34 @@ export function loadCustomThemeFromUrl(getOverride?: string): void { } } -type SharedTestSettings = [ - Mode | null, - Mode2 | null, - CustomText.CustomTextData | null, - boolean | null, - boolean | null, - string | null, - Difficulty | null, - string | null -]; +const testSettingsSchema = z.tuple([ + ModeSchema.nullable(), // Replaces z.union([ModeSchema, z.null()]) + Mode2Schema.nullable(), + CustomText.CustomTextDataSchema.nullable(), + z.boolean().nullable(), + z.boolean().nullable(), + z.string().nullable(), + DifficultySchema.nullable(), + z.string().nullable(), +]); + +type SharedTestSettings = z.infer; export function loadTestSettingsFromUrl(getOverride?: string): void { const getValue = Misc.findGetParameter("testSettings", getOverride); if (getValue === null) return; - const testSettingsSchema = z.tuple([ - z.union([ModeSchema, z.null()]), // Mode | null - z.union([Mode2Schema, z.null()]), // Mode2 | null - z.union([CustomText.customTextDataSchema, z.null()]), // CustomTextData | null - z.union([z.boolean(), z.null()]), // boolean | null - z.union([z.boolean(), z.null()]), // boolean | null - z.union([z.string(), z.null()]), // string | null - z.union([DifficultySchema, z.null()]), // Difficulty | null - z.union([z.string(), z.null()]), // string | null - ]); - let de: SharedTestSettings; try { const decompressed = decompressFromURI(getValue) ?? ""; - de = testSettingsSchema.parse( - JSON.parse(decompressed) - ) as SharedTestSettings; + const parsed = parseJsonWithSchema(decompressed, testSettingsSchema); + + // Ensure the second element (index 1) is a string or null + if (parsed[1] !== null && typeof parsed[1] === "number") { + parsed[1] = parsed[1].toString(); // Convert number to string + } + + de = parsed as SharedTestSettings; // Assign after refinement } catch (e) { console.error("Failed to parse test settings:", e); Notifications.add( From c422cb971ca128ad94551f193ade1864df820d45 Mon Sep 17 00:00:00 2001 From: Mohit Paddhariya Date: Fri, 24 Jan 2025 17:34:07 +0530 Subject: [PATCH 3/4] refactor: Update Zod schema naming and type handling (@dev-mohit06) --- frontend/src/ts/controllers/analytics-controller.ts | 6 +++--- frontend/src/ts/event-handlers/account.ts | 4 ++-- frontend/src/ts/test/custom-text.ts | 5 +---- frontend/src/ts/test/wikipedia.ts | 4 ++-- frontend/src/ts/utils/url-handler.ts | 8 +------- 5 files changed, 9 insertions(+), 18 deletions(-) diff --git a/frontend/src/ts/controllers/analytics-controller.ts b/frontend/src/ts/controllers/analytics-controller.ts index de43400880f7..afb7df31c37b 100644 --- a/frontend/src/ts/controllers/analytics-controller.ts +++ b/frontend/src/ts/controllers/analytics-controller.ts @@ -11,12 +11,12 @@ import { z } from "zod"; let analytics: AnalyticsType; -const acceptedCookiesSchema = z.object({ +const AcceptedCookiesSchema = z.object({ security: z.boolean(), analytics: z.boolean(), }); -type AcceptedCookies = z.infer; // Updated type inference +type AcceptedCookies = z.infer; export async function log( eventName: string, @@ -33,7 +33,7 @@ const lsString = localStorage.getItem("acceptedCookies"); let acceptedCookies: AcceptedCookies | null; if (lsString !== undefined && lsString !== null && lsString !== "") { try { - acceptedCookies = parseJsonWithSchema(lsString, acceptedCookiesSchema); + acceptedCookies = parseJsonWithSchema(lsString, AcceptedCookiesSchema); } catch (e) { console.error("Failed to parse accepted cookies:", e); acceptedCookies = null; diff --git a/frontend/src/ts/event-handlers/account.ts b/frontend/src/ts/event-handlers/account.ts index 10a41756a794..d9327ad794d0 100644 --- a/frontend/src/ts/event-handlers/account.ts +++ b/frontend/src/ts/event-handlers/account.ts @@ -38,7 +38,7 @@ $(accountPage).on("click", ".editProfileButton", () => { EditProfileModal.show(); }); -const tagsArraySchema = z.array(z.string()); +const TagsArraySchema = z.array(z.string()); $(accountPage).on("click", ".group.history .resultEditTagsButton", (e) => { const resultid = $(e.target).attr("data-result-id"); @@ -46,7 +46,7 @@ $(accountPage).on("click", ".group.history .resultEditTagsButton", (e) => { EditResultTagsModal.show( resultid ?? "", - parseJsonWithSchema(tags ?? "[]", tagsArraySchema), + parseJsonWithSchema(tags ?? "[]", TagsArraySchema), "accountPage" ); }); diff --git a/frontend/src/ts/test/custom-text.ts b/frontend/src/ts/test/custom-text.ts index 0e0662d70d07..9837fc554656 100644 --- a/frontend/src/ts/test/custom-text.ts +++ b/frontend/src/ts/test/custom-text.ts @@ -29,7 +29,7 @@ const customTextLongLS = new LocalStorageWithSchema({ fallback: {}, }); -const CustomTextSettingsSchema = z.object({ +export const CustomTextSettingsSchema = z.object({ text: z.array(z.string()), mode: CustomTextModeSchema, limit: z.object({ value: z.number(), mode: CustomTextLimitModeSchema }), @@ -66,9 +66,6 @@ const customTextSettings = new LocalStorageWithSchema({ }, }); -// reassigned to CustomTextSettingsSchema -export const CustomTextDataSchema = CustomTextSettingsSchema; - export function getText(): string[] { return customTextSettings.get().text; } diff --git a/frontend/src/ts/test/wikipedia.ts b/frontend/src/ts/test/wikipedia.ts index 883c50246f1e..44a616ce088b 100644 --- a/frontend/src/ts/test/wikipedia.ts +++ b/frontend/src/ts/test/wikipedia.ts @@ -244,7 +244,7 @@ type SectionObject = { }; // Section Schema -const sectionSchema = z.object({ +const SectionSchema = z.object({ query: z.object({ pages: z.record( z.string(), @@ -301,7 +301,7 @@ export async function getSection(language: string): Promise { if (sectionReq.status === 200) { const parsedResponse = parseJsonWithSchema( sectionReq.responseText, - sectionSchema + SectionSchema ); const page = parsedResponse.query.pages[pageid.toString()]; if (!page) { diff --git a/frontend/src/ts/utils/url-handler.ts b/frontend/src/ts/utils/url-handler.ts index b737c7d7f018..d55bca395bd4 100644 --- a/frontend/src/ts/utils/url-handler.ts +++ b/frontend/src/ts/utils/url-handler.ts @@ -135,7 +135,7 @@ export function loadCustomThemeFromUrl(getOverride?: string): void { const testSettingsSchema = z.tuple([ ModeSchema.nullable(), // Replaces z.union([ModeSchema, z.null()]) Mode2Schema.nullable(), - CustomText.CustomTextDataSchema.nullable(), + CustomText.CustomTextSettingsSchema.nullable(), z.boolean().nullable(), z.boolean().nullable(), z.string().nullable(), @@ -153,12 +153,6 @@ export function loadTestSettingsFromUrl(getOverride?: string): void { try { const decompressed = decompressFromURI(getValue) ?? ""; const parsed = parseJsonWithSchema(decompressed, testSettingsSchema); - - // Ensure the second element (index 1) is a string or null - if (parsed[1] !== null && typeof parsed[1] === "number") { - parsed[1] = parsed[1].toString(); // Convert number to string - } - de = parsed as SharedTestSettings; // Assign after refinement } catch (e) { console.error("Failed to parse test settings:", e); From 217c950542378fad38c4b50c9b9c30b2f900a94f Mon Sep 17 00:00:00 2001 From: Mohit Paddhariya Date: Sat, 25 Jan 2025 17:15:50 +0530 Subject: [PATCH 4/4] chore: resolve unresolved PR comments and update code comments as suggested --- frontend/src/ts/utils/url-handler.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/frontend/src/ts/utils/url-handler.ts b/frontend/src/ts/utils/url-handler.ts index d55bca395bd4..352a258ba7ad 100644 --- a/frontend/src/ts/utils/url-handler.ts +++ b/frontend/src/ts/utils/url-handler.ts @@ -132,18 +132,18 @@ export function loadCustomThemeFromUrl(getOverride?: string): void { } } -const testSettingsSchema = z.tuple([ - ModeSchema.nullable(), // Replaces z.union([ModeSchema, z.null()]) +const TestSettingsSchema = z.tuple([ + ModeSchema.nullable(), Mode2Schema.nullable(), CustomText.CustomTextSettingsSchema.nullable(), - z.boolean().nullable(), - z.boolean().nullable(), - z.string().nullable(), + z.boolean().nullable(), //punctuation + z.boolean().nullable(), //numbers + z.string().nullable(), //language DifficultySchema.nullable(), - z.string().nullable(), + z.string().nullable(), //funbox ]); -type SharedTestSettings = z.infer; +type SharedTestSettings = z.infer; export function loadTestSettingsFromUrl(getOverride?: string): void { const getValue = Misc.findGetParameter("testSettings", getOverride); @@ -152,7 +152,7 @@ export function loadTestSettingsFromUrl(getOverride?: string): void { let de: SharedTestSettings; try { const decompressed = decompressFromURI(getValue) ?? ""; - const parsed = parseJsonWithSchema(decompressed, testSettingsSchema); + const parsed = parseJsonWithSchema(decompressed, TestSettingsSchema); de = parsed as SharedTestSettings; // Assign after refinement } catch (e) { console.error("Failed to parse test settings:", e);