import { z, ZodSchema } from "zod"; import * as Shared from "./shared"; import * as Themes from "./themes"; import * as Layouts from "./layouts"; import { LanguageSchema } from "./languages"; import { FontNameSchema } from "./fonts"; export const SmoothCaretSchema = z.enum(["off", "slow", "medium", "fast"]); export type SmoothCaret = z.infer; export const QuickRestartSchema = z.enum(["off", "esc", "tab", "enter"]); export type QuickRestart = z.infer; export const QuoteLengthSchema = z.union([ z.literal(-3), z.literal(-2), z.literal(0), z.literal(1), z.literal(2), z.literal(3), ]); export type QuoteLength = z.infer; export const QuoteLengthConfigSchema = z .array(QuoteLengthSchema) .describe( [ "|value|description|\n|-|-|", "|-3|Favorite quotes|", "|-2|Quote search|", "|0|Short quotes|", "|1|Medium quotes|", "|2|Long quotes|", "|3|Thicc quotes|", ].join("\n"), ); export type QuoteLengthConfig = z.infer; export const CaretStyleSchema = z.enum([ "off", "default", "block", "outline", "underline", "carrot", "banana", "monkey", ]); export type CaretStyle = z.infer; export const ConfidenceModeSchema = z.enum(["off", "on", "max"]); export type ConfidenceMode = z.infer; export const IndicateTyposSchema = z.enum(["off", "below", "replace", "both"]); export type IndicateTypos = z.infer; export const CompositionDisplaySchema = z.enum(["off", "below", "replace"]); export type CompositionDisplay = z.infer; export const TimerStyleSchema = z.enum([ "off", "bar", "text", "mini", "flash_text", "flash_mini", ]); export type TimerStyle = z.infer; export const LiveSpeedAccBurstStyleSchema = z.enum(["off", "text", "mini"]); export type LiveSpeedAccBurstStyle = z.infer< typeof LiveSpeedAccBurstStyleSchema >; export const RandomThemeSchema = z.enum([ "off", "on", "fav", "light", "dark", "custom", "auto", ]); export type RandomTheme = z.infer; export const TimerColorSchema = z.enum(["black", "sub", "text", "main"]); export type TimerColor = z.infer; export const TimerOpacitySchema = z.enum(["0.25", "0.5", "0.75", "1"]); export type TimerOpacity = z.infer; export const StopOnErrorSchema = z.enum(["off", "word", "letter"]); export type StopOnError = z.infer; export const DeleteOnErrorSchema = z.enum([ "off", "letter", "letter_hard", "word", "word_hard", ]); export type DeleteOnError = z.infer; export const KeymapModeSchema = z.enum(["off", "static", "react", "next"]); export type KeymapMode = z.infer; export const KeymapStyleSchema = z.enum([ "staggered", "alice", "matrix", "split", "split_matrix", "steno", "steno_matrix", ]); export type KeymapStyle = z.infer; export const KeymapLegendStyleSchema = z.enum([ "lowercase", "uppercase", "blank", "dynamic", ]); export type KeymapLegendStyle = z.infer; export const KeymapKeysSchema = z.enum([ "minimal", //showTopRow=layout or showTopRow=never "minimal_numrow", //showTopRow=always "full", //include extra keys ]); export type KeymapKeys = z.infer; export const KeymapSizeSchema = z.number().min(0.5).max(3.5).step(0.1); export type KeymapSize = z.infer; export const SingleListCommandLineSchema = z.enum(["manual", "on"]); export type SingleListCommandLine = z.infer; export const PlaySoundOnErrorSchema = z.enum(["off", "1", "2", "3", "4"]); export type PlaySoundOnError = z.infer; export const PlaySoundOnClickSchema = z.enum([ "off", "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", ]); export type PlaySoundOnClick = z.infer; export const SoundVolumeSchema = z.number().min(0).max(1); export type SoundVolume = z.infer; export const PaceCaretSchema = z.enum([ "off", "average", "pb", "tagPb", "last", "custom", "daily", ]); export type PaceCaret = z.infer; export const AccountChartSchema = z.tuple([ z.enum(["on", "off"]), z.enum(["on", "off"]), z.enum(["on", "off"]), z.enum(["on", "off"]), ]); export type AccountChart = z.infer; export const MinimumWordsPerMinuteSchema = z.enum(["off", "custom"]); export type MinimumWordsPerMinute = z.infer; export const HighlightModeSchema = z.enum([ "off", "letter", "word", "next_word", "next_two_words", "next_three_words", ]); export type HighlightMode = z.infer; export const TypedEffectSchema = z.enum(["keep", "hide", "fade", "dots"]); export type TypedEffect = z.infer; export const TapeModeSchema = z.enum(["off", "letter", "word"]); export type TapeMode = z.infer; export const TapeMarginSchema = z.number().min(10).max(90); export type TapeMargin = z.infer; export const TypingSpeedUnitSchema = z.enum([ "wpm", "cpm", "wps", "cps", "wph", ]); export type TypingSpeedUnit = z.infer; export const AdsSchema = z.enum(["off", "result", "on", "sellout"]); export type Ads = z.infer; export const MinimumAccuracySchema = z.enum(["off", "custom"]); export type MinimumAccuracy = z.infer; export const RepeatQuotesSchema = z.enum(["off", "typing"]); export type RepeatQuotes = z.infer; export const OppositeShiftModeSchema = z.enum(["off", "on", "keymap"]); export type OppositeShiftMode = z.infer; export const CustomBackgroundSizeSchema = z.enum(["cover", "contain", "max"]); export type CustomBackgroundSize = z.infer; export const CustomBackgroundFilterSchema = z.tuple([ z.number(), z.number(), z.number(), z.number(), ]); export type CustomBackgroundFilter = z.infer< typeof CustomBackgroundFilterSchema >; export const CustomLayoutFluidSchema = z .array(Layouts.LayoutNameSchema) .min(2) .max(15); export type CustomLayoutFluid = z.infer; export const CustomPolyglotSchema = z.array(LanguageSchema).min(2); export type CustomPolyglot = z.infer; export const MonkeyPowerLevelSchema = z.enum(["off", "1", "2", "3", "4"]); export type MonkeyPowerLevel = z.infer; export const MinimumBurstSchema = z.enum(["off", "fixed", "flex"]); export type MinimumBurst = z.infer; export const ShowAverageSchema = z.enum(["off", "speed", "acc", "both"]); export type ShowAverage = z.infer; export const ShowPbSchema = z.boolean(); export type ShowPb = z.infer; export const ColorHexValueSchema = z.string().regex(/^#([\da-f]{3}){1,2}$/i); export type ColorHexValue = z.infer; export const DifficultySchema = Shared.DifficultySchema; export type Difficulty = Shared.Difficulty; export const CustomThemeColorsSchema = z.tuple([ ColorHexValueSchema, ColorHexValueSchema, ColorHexValueSchema, ColorHexValueSchema, ColorHexValueSchema, ColorHexValueSchema, ColorHexValueSchema, ColorHexValueSchema, ColorHexValueSchema, ColorHexValueSchema, ]); export type CustomThemeColors = z.infer; export const ThemeNameSchema = Themes.ThemeNameSchema; export type ThemeName = z.infer; export const FavThemesSchema = z.array(ThemeNameSchema); export type FavThemes = z.infer; export const FunboxNameSchema = z.enum([ "58008", "mirror", "upside_down", "nausea", "round_round_baby", "simon_says", "tts", "choo_choo", "arrows", "rAnDoMcAsE", "sPoNgEcAsE", "capitals", "layout_mirror", "layoutfluid", "earthquake", "space_balls", "gibberish", "ascii", "specials", "plus_zero", "plus_one", "plus_two", "plus_three", "read_ahead_easy", "read_ahead", "read_ahead_hard", "memory", "nospace", "poetry", "wikipedia", "weakspot", "pseudolang", "IPv4", "IPv6", "binary", "hexadecimal", "zipf", "morse", "crt", "backwards", "ddoouubblleedd", "instant_messaging", "underscore_spaces", "ALL_CAPS", "polyglot", "asl", "rot13", "no_quit", ]); export type FunboxName = z.infer; export const FunboxSchema = z.array(FunboxNameSchema).max(15); export type Funbox = z.infer; export const PaceCaretCustomSpeedSchema = z.number().nonnegative(); export type PaceCaretCustomSpeed = z.infer; export const MinWpmCustomSpeedSchema = z.number().nonnegative(); export type MinWpmCustomSpeed = z.infer; export const MinimumAccuracyCustomSchema = z.number().nonnegative().max(100); export type MinimumAccuracyCustom = z.infer; export const MinimumBurstCustomSpeedSchema = z.number().nonnegative(); export type MinimumBurstCustomSpeed = z.infer< typeof MinimumBurstCustomSpeedSchema >; export const TimeConfigSchema = z.number().int().nonnegative(); export type TimeConfig = z.infer; export const WordCountSchema = z.number().int().nonnegative(); export type WordCount = z.infer; export const KeymapLayoutSchema = z .literal("overrideSync") .or(Layouts.LayoutNameSchema); export type KeymapLayout = z.infer; export const LayoutSchema = z.literal("default").or(Layouts.LayoutNameSchema); export type Layout = z.infer; export const FontSizeSchema = z.number().positive(); export type FontSize = z.infer; export const MaxLineWidthSchema = z.number().min(20).max(1000).or(z.literal(0)); export type MaxLineWidth = z.infer; export const CustomBackgroundSchema = z .string() .url("Needs to be an URI") .regex(/^(https|http):\/\/.*/, "Unsupported protocol") .regex(/^[^`'"]*$/, "May not contain quotes") .regex(/.+(\.png|\.gif|\.jpeg|\.jpg|\.webp)/gi, "Unsupported image format") .max(2048, "URL is too long") .or(z.literal("")); export type CustomBackground = z.infer; export const PlayTimeWarningSchema = z .enum(["off", "1", "3", "5", "10"]) .describe( "How many seconds before the end of the test to play a warning sound.", ); export type PlayTimeWarning = z.infer; export const ConfigSchema = z .object({ // test punctuation: z.boolean(), numbers: z.boolean(), words: WordCountSchema, time: TimeConfigSchema, mode: Shared.ModeSchema, quoteLength: QuoteLengthConfigSchema, language: LanguageSchema, burstHeatmap: z.boolean(), // behavior difficulty: DifficultySchema, quickRestart: QuickRestartSchema, repeatQuotes: RepeatQuotesSchema, resultSaving: z.boolean(), blindMode: z.boolean(), alwaysShowWordsHistory: z.boolean(), singleListCommandLine: SingleListCommandLineSchema, minWpm: MinimumWordsPerMinuteSchema, minWpmCustomSpeed: MinWpmCustomSpeedSchema, minAcc: MinimumAccuracySchema, minAccCustom: MinimumAccuracyCustomSchema, minBurst: MinimumBurstSchema, minBurstCustomSpeed: MinimumBurstCustomSpeedSchema, britishEnglish: z.boolean(), funbox: FunboxSchema, customLayoutfluid: CustomLayoutFluidSchema, customPolyglot: CustomPolyglotSchema, // input freedomMode: z.boolean(), strictSpace: z.boolean(), oppositeShiftMode: OppositeShiftModeSchema, stopOnError: StopOnErrorSchema, deleteOnError: DeleteOnErrorSchema, confidenceMode: ConfidenceModeSchema, quickEnd: z.boolean(), indicateTypos: IndicateTyposSchema, compositionDisplay: CompositionDisplaySchema, hideExtraLetters: z.boolean(), lazyMode: z.boolean(), layout: LayoutSchema, codeUnindentOnBackspace: z.boolean(), // sound soundVolume: SoundVolumeSchema, playSoundOnClick: PlaySoundOnClickSchema, playSoundOnError: PlaySoundOnErrorSchema, playTimeWarning: PlayTimeWarningSchema, // caret smoothCaret: SmoothCaretSchema, caretStyle: CaretStyleSchema, paceCaret: PaceCaretSchema, paceCaretCustomSpeed: PaceCaretCustomSpeedSchema, paceCaretStyle: CaretStyleSchema, repeatedPace: z.boolean(), // appearance timerStyle: TimerStyleSchema, liveSpeedStyle: LiveSpeedAccBurstStyleSchema, liveAccStyle: LiveSpeedAccBurstStyleSchema, liveBurstStyle: LiveSpeedAccBurstStyleSchema, timerColor: TimerColorSchema, timerOpacity: TimerOpacitySchema, highlightMode: HighlightModeSchema, typedEffect: TypedEffectSchema, tapeMode: TapeModeSchema, tapeMargin: TapeMarginSchema, smoothLineScroll: z.boolean(), showAllLines: z.boolean(), alwaysShowDecimalPlaces: z.boolean(), typingSpeedUnit: TypingSpeedUnitSchema, startGraphsAtZero: z.boolean(), maxLineWidth: MaxLineWidthSchema, fontSize: FontSizeSchema, fontFamily: FontNameSchema, keymapMode: KeymapModeSchema, keymapLayout: KeymapLayoutSchema, keymapStyle: KeymapStyleSchema, keymapLegendStyle: KeymapLegendStyleSchema, keymapKeys: KeymapKeysSchema, keymapSize: KeymapSizeSchema, // theme flipTestColors: z.boolean(), colorfulMode: z.boolean(), customBackground: CustomBackgroundSchema, customBackgroundSize: CustomBackgroundSizeSchema, customBackgroundFilter: CustomBackgroundFilterSchema, autoSwitchTheme: z.boolean(), themeLight: ThemeNameSchema, themeDark: ThemeNameSchema, randomTheme: RandomThemeSchema, favThemes: FavThemesSchema, theme: ThemeNameSchema, customTheme: z.boolean(), customThemeColors: CustomThemeColorsSchema, // hide elements showKeyTips: z.boolean(), showOutOfFocusWarning: z.boolean(), capsLockWarning: z.boolean(), showAverage: ShowAverageSchema, showPb: ShowPbSchema, // other (hidden) accountChart: AccountChartSchema, monkey: z.boolean(), monkeyPowerLevel: MonkeyPowerLevelSchema, // ads ads: AdsSchema, } satisfies Record) .strict(); export type Config = z.infer; export const ConfigKeySchema = ConfigSchema.keyof(); export type ConfigKey = z.infer; export type ConfigValue = Config[keyof Config]; export const PartialConfigSchema = ConfigSchema.partial(); export type PartialConfig = z.infer; export const ConfigGroupNameSchema = z.enum([ "test", "behavior", "input", "sound", "caret", "appearance", "theme", "hideElements", "hidden", "ads", ]); export type ConfigGroupName = z.infer;