From 1789f36a63ce056b1086cff52d5b415c07eb8af5 Mon Sep 17 00:00:00 2001 From: Alexis Faizeau Date: Mon, 10 Jan 2022 17:40:04 +0100 Subject: [PATCH] Implement zod checking on translator compiler --- front/package.json | 3 +- front/src/Translator/TranslationCompiler.ts | 44 +++++++++++++++------ front/src/Translator/Translator.ts | 14 +++---- front/src/define-plugin.d.ts | 2 +- front/yarn.lock | 5 +++ 5 files changed, 48 insertions(+), 20 deletions(-) diff --git a/front/package.json b/front/package.json index c7b819bd..81da765c 100644 --- a/front/package.json +++ b/front/package.json @@ -65,7 +65,8 @@ "socket.io-client": "^2.3.0", "standardized-audio-context": "^25.2.4", "ts-proto": "^1.96.0", - "uuidv4": "^6.2.10" + "uuidv4": "^6.2.10", + "zod": "^3.11.6" }, "scripts": { "start": "run-p templater serve svelte-check-watch", diff --git a/front/src/Translator/TranslationCompiler.ts b/front/src/Translator/TranslationCompiler.ts index fe83f41f..e13c134e 100644 --- a/front/src/Translator/TranslationCompiler.ts +++ b/front/src/Translator/TranslationCompiler.ts @@ -1,4 +1,5 @@ import fs from "fs"; +import { z } from "zod"; export type LanguageFound = { id: string; @@ -7,6 +8,10 @@ export type LanguageFound = { default: boolean; }; +type LanguageObject = { + [key: string]: string | boolean | LanguageObject; +}; + const translationsBasePath = "./translations"; const fallbackLanguage = process.env.FALLBACK_LANGUAGE || "en-US"; @@ -27,17 +32,23 @@ const getAllLanguagesByFiles = (dirPath: string, languages: Array const rawData = fs.readFileSync(dirPath + "/" + file, "utf-8"); const languageObject = JSON.parse(rawData); - if ( - "language" in languageObject && typeof languageObject.language === "string" && - "country" in languageObject && typeof languageObject.country === "string" && - "default" in languageObject && typeof languageObject.default === "boolean" - ) { + const indexLanguageObject = z.object({ + language: z.string(), + country: z.string(), + default: z.boolean(), + }); + + try { + const indexLanguage = indexLanguageObject.parse(languageObject); + languages?.push({ id: parts[1], - language: languageObject.language, - country: languageObject.country, - default: languageObject.default + language: indexLanguage.language, + country: indexLanguage.country, + default: indexLanguage.default, }); + } catch (e) { + console.error(e); } } }); @@ -45,7 +56,7 @@ const getAllLanguagesByFiles = (dirPath: string, languages: Array return languages; }; -const getFallbackLanguageObject = (dirPath: string, languageObject: Object | undefined) => { +const getFallbackLanguageObject = (dirPath: string, languageObject: LanguageObject | undefined) => { const files = fs.readdirSync(dirPath); languageObject = languageObject || {}; @@ -59,8 +70,19 @@ const getFallbackLanguageObject = (dirPath: string, languageObject: Object | und return; } - const rawData = fs.readFileSync(dirPath + "/" + file, "utf-8"); - languageObject = { ...languageObject, ...JSON.parse(rawData) }; + const data = JSON.parse(fs.readFileSync(dirPath + "/" + file, "utf-8")); + + try { + const languageObjectFormat: z.ZodType = z.lazy(() => { + return z.object({}).catchall(z.union([z.string(), z.boolean(), languageObjectFormat])); + }); + + const languageObjectData = languageObjectFormat.parse(data); + + languageObject = { ...languageObject, ...languageObjectData }; + } catch (e) { + console.error(e); + } } }); diff --git a/front/src/Translator/Translator.ts b/front/src/Translator/Translator.ts index df1539dc..b8af8e05 100644 --- a/front/src/Translator/Translator.ts +++ b/front/src/Translator/Translator.ts @@ -5,10 +5,6 @@ export type Language = { country: string; }; -type LanguageObject = { - [key: string]: string | LanguageObject; -}; - type TranslationParams = { [key: string]: string | number; }; @@ -19,7 +15,7 @@ class Translator { country: "US", }; - private readonly fallbackLanguageObject: LanguageObject = FALLBACK_LANGUAGE_OBJECT as LanguageObject; + private readonly fallbackLanguageObject: LanguageObject = FALLBACK_LANGUAGE_OBJECT; /** * Current language @@ -186,10 +182,14 @@ class Translator { */ private getObjectValueByPath(key: string, object: LanguageObject): string | undefined { const paths = key.split("."); - let currentValue: LanguageObject | string = object; + let currentValue: string | boolean | LanguageObject = object; for (const path of paths) { - if (typeof currentValue === "string" || currentValue[path] === undefined) { + if ( + typeof currentValue === "string" || + typeof currentValue === "boolean" || + currentValue[path] === undefined + ) { return undefined; } diff --git a/front/src/define-plugin.d.ts b/front/src/define-plugin.d.ts index b43443ec..8987e134 100644 --- a/front/src/define-plugin.d.ts +++ b/front/src/define-plugin.d.ts @@ -1,5 +1,5 @@ type LanguageObject = { - [key: string]: string | LanguageObject; + [key: string]: string | boolean | LanguageObject; }; type LanguageFound = { diff --git a/front/yarn.lock b/front/yarn.lock index d6768844..b84ed603 100644 --- a/front/yarn.lock +++ b/front/yarn.lock @@ -6553,3 +6553,8 @@ yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +zod@^3.11.6: + version "3.11.6" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.11.6.tgz#e43a5e0c213ae2e02aefe7cb2b1a6fa3d7f1f483" + integrity sha512-daZ80A81I3/9lIydI44motWe6n59kRBfNzTuS2bfzVh1nAXi667TOTWWtatxyG+fwgNUiagSj/CWZwRRbevJIg==