From b1727ecceaa4bd7e6f9108dbe089953efffaef26 Mon Sep 17 00:00:00 2001 From: Miodec Date: Wed, 24 Jun 2026 19:22:03 +0200 Subject: [PATCH 1/2] refactor: move state --- frontend/src/ts/elements/keymap.ts | 4 ++-- frontend/src/ts/test/test-logic.ts | 2 +- frontend/src/ts/test/test-state.ts | 5 +++++ frontend/src/ts/test/test-words.ts | 5 ----- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/frontend/src/ts/elements/keymap.ts b/frontend/src/ts/elements/keymap.ts index b469b344bb86..ec8d63539017 100644 --- a/frontend/src/ts/elements/keymap.ts +++ b/frontend/src/ts/elements/keymap.ts @@ -6,7 +6,6 @@ import * as JSONData from "../utils/json-data"; import * as Hangul from "hangul-js"; import { showErrorNotification } from "../states/notifications"; import { getActivePage } from "../states/core"; -import * as TestWords from "../test/test-words"; import { onCapsLockChange, isCapsLockOn } from "@leonabcd123/modern-caps-lock"; import * as ShiftTracker from "../test/shift-tracker"; import * as AltTracker from "../test/alt-tracker"; @@ -20,6 +19,7 @@ import { requestDebouncedAnimationFrame } from "../utils/debounced-animation-fra import { getTheme } from "../states/theme"; import { createEffectOn } from "../hooks/effects"; +import { wordsHaveNumbers } from "../test/test-state"; export const keyDataDelimiter = "\uE000"; const keymap = qsr("#keymap"); @@ -431,7 +431,7 @@ export async function refresh(): Promise { } const showTopRow = - (TestWords.hasNumbers && Config.keymapMode === "next") || + (wordsHaveNumbers && Config.keymapMode === "next") || Config.keymapShowTopRow === "always" || (layoutData.keymapShowTopRow && Config.keymapShowTopRow !== "never"); diff --git a/frontend/src/ts/test/test-logic.ts b/frontend/src/ts/test/test-logic.ts index 320f71ec448e..7255ba66f396 100644 --- a/frontend/src/ts/test/test-logic.ts +++ b/frontend/src/ts/test/test-logic.ts @@ -587,7 +587,7 @@ async function init(): Promise { } } - TestWords.setHasNumbers(hasNumbers); + TestState.setWordsHaveNumbers(hasNumbers); setWordsHaveTab(wordsHaveTab); setWordsHaveNewline(wordsHaveNewline); diff --git a/frontend/src/ts/test/test-state.ts b/frontend/src/ts/test/test-state.ts index 72ed351cd9eb..59628dca46bf 100644 --- a/frontend/src/ts/test/test-state.ts +++ b/frontend/src/ts/test/test-state.ts @@ -14,6 +14,11 @@ export let resultVisible = false; export let resultCalculating = false; export let koreanStatus = false; export let lastEventLog: EventLog | null = null; +export let wordsHaveNumbers = false; + +export function setWordsHaveNumbers(val: boolean): void { + wordsHaveNumbers = val; +} export function setLastEventLog(log: EventLog): void { lastEventLog = log; diff --git a/frontend/src/ts/test/test-words.ts b/frontend/src/ts/test/test-words.ts index b8ddae67d6ff..252639a05301 100644 --- a/frontend/src/ts/test/test-words.ts +++ b/frontend/src/ts/test/test-words.ts @@ -56,8 +56,3 @@ class Words { } export const words = new Words(); -export let hasNumbers = false; - -export function setHasNumbers(tf: boolean): void { - hasNumbers = tf; -} From 8d51a920da335b28603124f66ce8b50b432e7eaf Mon Sep 17 00:00:00 2001 From: Jack Date: Thu, 25 Jun 2026 00:06:47 +0200 Subject: [PATCH 2/2] refactor: update getter type (@miodec) (#8158) Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../src/ts/input/helpers/word-navigation.ts | 6 ++++-- frontend/src/ts/test/british-english.ts | 8 ++++++-- frontend/src/ts/test/pace-caret.ts | 10 +++++++--- frontend/src/ts/test/practise-words.ts | 17 ++++++++--------- frontend/src/ts/test/test-logic.ts | 4 +++- frontend/src/ts/test/test-ui.ts | 10 ++++++---- frontend/src/ts/test/test-words.ts | 2 +- frontend/src/ts/test/words-generator.ts | 15 +++++++++------ 8 files changed, 44 insertions(+), 28 deletions(-) diff --git a/frontend/src/ts/input/helpers/word-navigation.ts b/frontend/src/ts/input/helpers/word-navigation.ts index 947d77541858..ba34c4267c7a 100644 --- a/frontend/src/ts/input/helpers/word-navigation.ts +++ b/frontend/src/ts/input/helpers/word-navigation.ts @@ -57,7 +57,8 @@ export async function goToNextWord({ PaceCaret.handleSpace(correctInsert, TestWords.words.getCurrentText()); - Funbox.toggleScript(TestWords.words.getText(TestState.activeWordIndex + 1)); + const nextWord = TestWords.words.getText(TestState.activeWordIndex + 1); + if (nextWord !== undefined) Funbox.toggleScript(nextWord); const lastWord = TestState.activeWordIndex >= TestWords.words.length - 1; if (lastWord) { @@ -97,7 +98,8 @@ export function goToPreviousWord( TestState.decreaseActiveWordIndex(); - Funbox.toggleScript(TestWords.words.getText(TestState.activeWordIndex)); + const word = TestWords.words.getText(TestState.activeWordIndex); + if (word !== undefined) Funbox.toggleScript(word); const nospaceEnabled = isFunboxActiveWithProperty("nospace"); diff --git a/frontend/src/ts/test/british-english.ts b/frontend/src/ts/test/british-english.ts index 35d0bf7e1dca..00b32b5ea5e1 100644 --- a/frontend/src/ts/test/british-english.ts +++ b/frontend/src/ts/test/british-english.ts @@ -4,7 +4,7 @@ import { capitalizeFirstLetterOfEachWord } from "../utils/strings"; export async function replace( word: string, - previousWord: string, + previousWord: string | undefined, ): Promise { // Convert American-style double quotes to British-style single quotes if (word.includes('"')) { @@ -38,7 +38,11 @@ export async function replace( ? [rule, []] : [rule.britishWord, rule.exceptPreviousWords]; - if (Config.mode === "quote" && exceptions.includes(previousWord)) { + if ( + Config.mode === "quote" && + previousWord !== undefined && + exceptions.includes(previousWord) + ) { return word; } diff --git a/frontend/src/ts/test/pace-caret.ts b/frontend/src/ts/test/pace-caret.ts index 27244a9b6452..28f962156672 100644 --- a/frontend/src/ts/test/pace-caret.ts +++ b/frontend/src/ts/test/pace-caret.ts @@ -180,7 +180,8 @@ function incrementLetterIndex(): void { settings.currentLetterIndex++; if ( settings.currentLetterIndex >= - TestWords.words.getText(settings.currentWordIndex).length + 1 + // oxlint-disable-next-line typescript/no-non-null-assertion let it throw if undefined + TestWords.words.getText(settings.currentWordIndex)!.length + 1 ) { //go to the next word settings.currentLetterIndex = 0; @@ -193,7 +194,9 @@ function incrementLetterIndex(): void { if (settings.currentLetterIndex <= -2) { //go to the previous word settings.currentLetterIndex = - TestWords.words.getText(settings.currentWordIndex - 1).length - 1; + // oxlint-disable-next-line typescript/no-non-null-assertion let it throw if undefined + TestWords.words.getText(settings.currentWordIndex - 1)!.length - + 1; settings.currentWordIndex--; } settings.correction++; @@ -203,7 +206,8 @@ function incrementLetterIndex(): void { settings.currentLetterIndex++; if ( settings.currentLetterIndex >= - TestWords.words.getText(settings.currentWordIndex).length + // oxlint-disable-next-line typescript/no-non-null-assertion let it throw if undefined + TestWords.words.getText(settings.currentWordIndex)!.length ) { //go to the next word settings.currentLetterIndex = 0; diff --git a/frontend/src/ts/test/practise-words.ts b/frontend/src/ts/test/practise-words.ts index 49a384d8f8bd..978304c28f60 100644 --- a/frontend/src/ts/test/practise-words.ts +++ b/frontend/src/ts/test/practise-words.ts @@ -64,17 +64,16 @@ export function init( if (missed === "biwords") { for (let i = 0; i < TestWords.words.length; i++) { const missedWord = TestWords.words.getText(i); + + if (missedWord === undefined) continue; // won't happen, but ts complains + const missedWordCount = missedWords[missedWord]; if (missedWordCount !== undefined) { - if (i === 0) { - sortableMissedBiwords.push([missedWord, "", missedWordCount]); - } else { - sortableMissedBiwords.push([ - missedWord, - TestWords.words.getText(i - 1), - missedWordCount, - ]); - } + sortableMissedBiwords.push([ + missedWord, + TestWords.words.getText(i - 1) ?? "", + missedWordCount, + ]); } } sortableMissedBiwords.sort((a, b) => { diff --git a/frontend/src/ts/test/test-logic.ts b/frontend/src/ts/test/test-logic.ts index 7255ba66f396..e5b47d0eb492 100644 --- a/frontend/src/ts/test/test-logic.ts +++ b/frontend/src/ts/test/test-logic.ts @@ -1079,7 +1079,9 @@ export async function finish(difficultyFailed = false): Promise { const lastWordInputLength = history[wordIndex]?.length ?? 0; - if (lastWordInputLength < TestWords.words.getText(wordIndex).length) { + if ( + lastWordInputLength < (TestWords.words.getText(wordIndex)?.length ?? 0) + ) { historyLength--; } diff --git a/frontend/src/ts/test/test-ui.ts b/frontend/src/ts/test/test-ui.ts index 3035080af0c3..89f919421701 100644 --- a/frontend/src/ts/test/test-ui.ts +++ b/frontend/src/ts/test/test-ui.ts @@ -501,7 +501,9 @@ function showWords(): void { } else { let wordsHTML = ""; for (let i = 0; i < TestWords.words.length; i++) { - wordsHTML += buildWordHTML(TestWords.words.getText(i), i); + const word = TestWords.words.getText(i); + if (word === undefined) continue; // won't happen, but ts complains + wordsHTML += buildWordHTML(word, i); } wordsEl.setHtml(wordsHTML); } @@ -737,7 +739,7 @@ export async function updateWordLetters({ async () => { pendingWordData.delete(wordIndex); const currentWord = TestWords.words.getText(wordIndex); - if (!currentWord && Config.mode !== "zen") return; + if (currentWord === undefined && Config.mode !== "zen") return; let ret = ""; const wordAtIndex = getWordElement(wordIndex); if (!wordAtIndex) return; @@ -767,7 +769,7 @@ export async function updateWordLetters({ const funbox = findSingleActiveFunboxWithFunction("getWordHtml"); const inputChars = Strings.splitIntoCharacters(input); - const currentWordChars = Strings.splitIntoCharacters(currentWord); + const currentWordChars = Strings.splitIntoCharacters(currentWord ?? ""); for (let i = 0; i < inputChars.length; i++) { const charCorrect = currentWordChars[i] === inputChars[i]; @@ -867,7 +869,7 @@ export async function updateWordLetters({ hintsHtml = createHintsHtml( hintIndices, wordAtIndexLetters, - currentWord, + currentWord ?? "", ); } else { hintsHtml = createHintsHtml(hintIndices, wordAtIndexLetters, input); diff --git a/frontend/src/ts/test/test-words.ts b/frontend/src/ts/test/test-words.ts index 252639a05301..63b30a92b7f1 100644 --- a/frontend/src/ts/test/test-words.ts +++ b/frontend/src/ts/test/test-words.ts @@ -12,7 +12,7 @@ class Words { } getText(i?: undefined, raw?: boolean): string[]; - getText(i: number, raw?: boolean): string; + getText(i: number, raw?: boolean): string | undefined; getText(i?: number, raw = false): string | string[] | undefined { if (i === undefined) { return this.list; diff --git a/frontend/src/ts/test/words-generator.ts b/frontend/src/ts/test/words-generator.ts index 95895c4ddbfd..52a3c9c1e4d2 100644 --- a/frontend/src/ts/test/words-generator.ts +++ b/frontend/src/ts/test/words-generator.ts @@ -38,7 +38,7 @@ function shouldCapitalize(lastChar: string): boolean { let spanishSentenceTracker = ""; export async function punctuateWord( - previousWord: string, + previousWord: string | undefined, currentWord: string, index: number, maxindex: number, @@ -47,7 +47,8 @@ export async function punctuateWord( const currentLanguage = Config.language.split("_")[0]; - const lastChar = Strings.getLastChar(previousWord); + const lastChar = + previousWord !== undefined ? Strings.getLastChar(previousWord) : undefined; const funbox = findSingleActiveFunboxWithFunction("punctuateWord"); if (funbox) { @@ -56,7 +57,7 @@ export async function punctuateWord( if ( currentLanguage !== "code" && currentLanguage !== "georgian" && - (index === 0 || shouldCapitalize(lastChar)) + (index === 0 || (lastChar !== undefined && shouldCapitalize(lastChar))) ) { //always capitalise the first word or if there was a dot unless using a code alphabet or the Georgian language @@ -371,7 +372,7 @@ function applyFunboxesToWord( async function applyBritishEnglishToWord( word: string, - previousWord: string, + previousWord: string | undefined, ): Promise { if (!Config.britishEnglish) return word; if (!Config.language.includes("english")) return word; @@ -743,7 +744,7 @@ type GetNextWordReturn = { export async function getNextWord( wordIndex: number, wordsBound: number, - previousWord: string, + previousWord: string | undefined, previousWord2: string | undefined, ): Promise { console.debug("Getting next word", { @@ -807,7 +808,9 @@ export async function getNextWord( const funboxFrequency = getFunboxWordsFrequency() ?? "normal"; let randomWord = currentWordset.randomWord(funboxFrequency); - const previousWordRaw = previousWord.replace(/[.?!":\-,]/g, "").toLowerCase(); + const previousWordRaw = previousWord + ?.replace(/[.?!":\-,]/g, "") + .toLowerCase(); const previousWord2Raw = previousWord2 ?.replace(/[.?!":\-,']/g, "") .toLowerCase();