From ab614203cb92e18c3d7ea62ce9cc2a06dd9c571a Mon Sep 17 00:00:00 2001 From: Miodec Date: Mon, 3 Aug 2026 18:14:39 +0100 Subject: [PATCH 1/2] feat: add delete on error --- .../input/handlers/insert-text.spec.ts | 412 ++++++++++++++++++ .../input/helpers/fail-or-finish.spec.ts | 26 ++ .../input/helpers/validation.spec.ts | 38 ++ frontend/__tests__/test/events/stats.spec.ts | 199 ++++++++- .../ts/commandline/commandline-metadata.ts | 6 + frontend/src/ts/commandline/lists.ts | 1 + .../pages/settings/SettingsPage.tsx | 1 + .../test/modes-notice/TestModesNotice.tsx | 14 + frontend/src/ts/config/metadata.tsx | 20 + frontend/src/ts/constants/default-config.ts | 1 + .../ts/input/handlers/before-insert-text.ts | 18 +- frontend/src/ts/input/handlers/insert-text.ts | 80 +++- .../src/ts/input/helpers/fail-or-finish.ts | 5 +- frontend/src/ts/input/helpers/validation.ts | 5 + frontend/src/ts/test/events/types.ts | 5 + frontend/src/ts/test/result.ts | 3 + packages/schemas/src/configs.ts | 10 + 17 files changed, 832 insertions(+), 12 deletions(-) create mode 100644 frontend/__tests__/input/handlers/insert-text.spec.ts diff --git a/frontend/__tests__/input/handlers/insert-text.spec.ts b/frontend/__tests__/input/handlers/insert-text.spec.ts new file mode 100644 index 000000000000..5b961698d3e5 --- /dev/null +++ b/frontend/__tests__/input/handlers/insert-text.spec.ts @@ -0,0 +1,412 @@ +import { describe, it, expect, beforeEach, vi } from "vitest"; + +// The input element and the event log are the two things delete-on-error +// writes to, and they must agree. The element is faked (mirroring the real +// module, fake leading space included) and the event log is the real one, so +// these tests assert the actual events onInsertText emits. +const inputEl = vi.hoisted(() => ({ value: " " })); + +vi.mock("../../../src/ts/input/input-element", () => ({ + getInputElementValue: () => ({ + inputValue: inputEl.value.slice(1), + realInputValue: inputEl.value, + }), + setInputElementValue: (value: string) => { + inputEl.value = ` ${value}`; + }, + appendToInputElementValue: (value: string) => { + inputEl.value += value; + }, + replaceInputElementLastValueChar: (char: string) => { + inputEl.value = ` ${inputEl.value.slice(1).slice(0, -1)}${char}`; + }, + getInputElement: () => null, + moveInputElementCaretToTheEnd: () => undefined, + isInputElementFocused: () => true, + focusInputElement: () => undefined, + blurInputElement: () => undefined, +})); + +const mockState = vi.hoisted(() => ({ + activeWordIndex: 0, + correctShiftUsed: true as boolean, +})); + +const nav = vi.hoisted(() => ({ + goToNextWord: vi.fn(), + goToPreviousWord: vi.fn(), +})); +vi.mock("../../../src/ts/input/helpers/word-navigation", () => nav); + +vi.mock("../../../src/ts/test/test-words", () => { + type CommitChar = " " | "\n" | ""; + type Word = { text: string; textWithCommit: string; commit: CommitChar }; + const list: Word[] = []; + return { + words: { + list, + get: (index?: number) => (index === undefined ? [...list] : list[index]), + getCurrent: () => list[mockState.activeWordIndex], + push(word: string, _index?: number) { + let commit: CommitChar = ""; + if (word.endsWith(" ")) { + commit = " "; + word = word.slice(0, -1); + } else if (word.endsWith("\n")) { + commit = "\n"; + word = word.slice(0, -1); + } + list.push({ text: word, textWithCommit: word + commit, commit }); + }, + reset() { + list.length = 0; + }, + get length() { + return list.length; + }, + }, + }; +}); + +vi.mock("../../../src/ts/states/test", () => ({ + getActiveWordIndex: () => mockState.activeWordIndex, + isTestActive: () => true, + isResultCalculating: () => false, + isTestRestarting: () => false, + wordsHaveNewline: () => false, + getCurrentQuote: () => null, + getBailedOut: () => false, + getKoreanStatus: () => false, +})); + +vi.mock("../../../src/ts/input/state", () => ({ + isCorrectShiftUsed: () => mockState.correctShiftUsed, + getIncorrectShiftsInARow: () => 0, + incrementIncorrectShiftsInARow: () => undefined, + resetIncorrectShiftsInARow: () => undefined, + isAwaitingNextWord: () => false, +})); + +vi.mock("../../../src/ts/test/custom-text", () => ({ + getLimit: () => ({ mode: "words", value: 0 }), +})); + +// peripheral collaborators - none of them feed back into the events we assert +vi.mock("../../../src/ts/test/test-ui", () => ({ + afterTestTextInput: vi.fn(), + pendingWordData: new Map(), +})); +vi.mock("../../../src/ts/test/test-logic", () => ({ + startTest: vi.fn(), + fail: vi.fn(), + finish: vi.fn(), + addWord: vi.fn(), +})); +vi.mock("../../../src/ts/test/weak-spot", () => ({ updateScore: vi.fn() })); +vi.mock("../../../src/ts/events/keymap", () => ({ flash: vi.fn() })); +vi.mock("../../../src/ts/states/notifications", () => ({ + showNoticeNotification: vi.fn(), +})); +vi.mock("../../../src/ts/legacy-states/composition", () => ({ + getComposing: () => false, + getData: () => "", +})); +vi.mock("../../../src/ts/test/words-generator", () => ({ + areAllWordsGenerated: () => true, +})); +vi.mock("../../../src/ts/input/handlers/before-insert-text", () => ({ + onBeforeInsertText: () => false, +})); +vi.mock("../../../src/ts/input/helpers/fail-or-finish", () => ({ + checkIfFailedDueToDifficulty: () => false, + checkIfFailedDueToMinBurst: () => false, + checkIfFinished: () => false, +})); + +import { onInsertText } from "../../../src/ts/input/handlers/insert-text"; +import { + resetTestEvents, + getAllTestEvents, + getInputForWord, +} from "../../../src/ts/test/events/data"; +import { + findInputValueMismatches, + getEventsForWord, +} from "../../../src/ts/test/events/helpers"; +import type { InputEventNoMs } from "../../../src/ts/test/events/types"; +import { words as TestWords } from "../../../src/ts/test/test-words"; +import { __testing } from "../../../src/ts/config/testing"; +import { DeleteInputType } from "../../../src/ts/input/helpers/input-type"; + +const { replaceConfig } = __testing; + +function setInput(value: string): void { + inputEl.value = ` ${value}`; +} +function getInput(): string { + return inputEl.value.slice(1); +} + +// mirrors goToNextWord's observable effects: clear the input, advance the word +nav.goToNextWord.mockImplementation(async () => { + setInput(""); + mockState.activeWordIndex++; + return { increasedWordIndex: true, lastBurst: null }; +}); + +// mirrors goToPreviousWord (minus the nospace branch): step back a word and +// restore that word's input, dropping its separator for a single backspace +nav.goToPreviousWord.mockImplementation((inputType: DeleteInputType) => { + if (mockState.activeWordIndex === 0) { + setInput(""); + return; + } + mockState.activeWordIndex--; + if (inputType === "deleteWordBackward") { + setInput(""); + return; + } + const word = getInputForWord(mockState.activeWordIndex); + setInput( + word.endsWith("\n") || word.endsWith(" ") ? word.slice(0, -1) : word, + ); +}); + +function pushWords(...words: string[]): void { + words.forEach((word, i) => { + TestWords.push(i === words.length - 1 ? word : `${word} `, i); + }); +} + +// mirrors emulateInsertText: the character is in the element before the +// handler runs, which is what handleDeleteOnError's length maths relies on +async function type(data: string, now = 1000): Promise { + inputEl.value += data; + await onInsertText({ data, now }); +} + +function inputEventsForWord(wordIndex: number): InputEventNoMs[] { + return getEventsForWord(getAllTestEvents(), wordIndex).filter( + (e): e is InputEventNoMs => e.type === "input", + ); +} + +/** The deletion events only, as `[inputType, charIndex, inputValue]` triples. */ +function deletesForWord( + wordIndex: number, +): [string, number, string | undefined][] { + return inputEventsForWord(wordIndex) + .filter((e) => e.data.inputType.startsWith("delete")) + .map((e) => [e.data.inputType, e.data.charIndex, e.data.inputValue]); +} + +describe("onInsertText - delete on error", () => { + beforeEach(() => { + vi.clearAllMocks(); + resetTestEvents(); + TestWords.reset(); + mockState.activeWordIndex = 0; + mockState.correctShiftUsed = true; + setInput(""); + replaceConfig({ + mode: "words", + language: "english", + deleteOnError: "letter", + stopOnError: "off", + difficulty: "normal", + strictSpace: false, + oppositeShiftMode: "off", + keymapMode: "off", + blindMode: false, + }); + }); + + describe("letter mode", () => { + it("deletes the incorrect char and the one before it", async () => { + pushWords("hello", "world"); + await type("h"); + await type("e"); + await type("x"); + + expect(deletesForWord(0)).toEqual([ + ["deleteContentBackward", 3, "he"], + ["deleteContentBackward", 2, "h"], + ]); + expect(getInput()).toBe("h"); + expect(findInputValueMismatches(inputEventsForWord(0))).toEqual([]); + }); + + it("deletes only the incorrect char at the start of a word", async () => { + pushWords("hello", "world"); + await type("x"); + + expect(deletesForWord(0)).toEqual([["deleteContentBackward", 1, ""]]); + expect(getInput()).toBe(""); + expect(findInputValueMismatches(inputEventsForWord(0))).toEqual([]); + }); + + it("does not go back a word without a hard variant", async () => { + pushWords("hello", "world"); + await type("h"); + await type("e"); + await type("l"); + await type("l"); + await type("o"); + await type(" "); + expect(mockState.activeWordIndex).toBe(1); + + await type("x"); + + expect(nav.goToPreviousWord).not.toHaveBeenCalled(); + expect(mockState.activeWordIndex).toBe(1); + }); + + it("deletes an incorrect separator instead of committing the word", async () => { + pushWords("hello", "world"); + await type("h"); + await type("e"); + await type(" "); + + expect(nav.goToNextWord).not.toHaveBeenCalled(); + expect(mockState.activeWordIndex).toBe(0); + expect(deletesForWord(0)).toEqual([ + ["deleteContentBackward", 3, "he"], + ["deleteContentBackward", 2, "h"], + ]); + expect(findInputValueMismatches(inputEventsForWord(0))).toEqual([]); + }); + }); + + describe("word mode", () => { + beforeEach(() => { + replaceConfig({ deleteOnError: "word", stopOnError: "off" }); + }); + + it("clears the whole word in one event", async () => { + pushWords("hello", "world"); + await type("h"); + await type("e"); + await type("x"); + + expect(deletesForWord(0)).toEqual([["deleteWordBackward", 3, ""]]); + expect(getInput()).toBe(""); + expect(findInputValueMismatches(inputEventsForWord(0))).toEqual([]); + }); + }); + + describe("hard variants", () => { + it("letter_hard regresses on a first-char mistake", async () => { + replaceConfig({ deleteOnError: "letter_hard", stopOnError: "off" }); + pushWords("hello", "world"); + for (const char of "hello ") await type(char); + expect(mockState.activeWordIndex).toBe(1); + + await type("x"); + + expect(nav.goToPreviousWord).toHaveBeenCalledWith( + "deleteContentBackward", + ); + expect(mockState.activeWordIndex).toBe(0); + // the incorrect char is deleted from the word it was typed in... + expect(deletesForWord(1)).toEqual([["deleteContentBackward", 1, ""]]); + // ...then the regression lands on the previous word, separator removed + expect(deletesForWord(0)).toEqual([ + ["deleteContentBackward", 5, "hello"], + ]); + expect(getInput()).toBe("hello"); + expect(findInputValueMismatches(inputEventsForWord(0))).toEqual([]); + expect(findInputValueMismatches(inputEventsForWord(1))).toEqual([]); + }); + + it("word_hard clears the word it regresses into", async () => { + replaceConfig({ deleteOnError: "word_hard", stopOnError: "off" }); + pushWords("hello", "world"); + for (const char of "hello ") await type(char); + + await type("x"); + + expect(nav.goToPreviousWord).toHaveBeenCalledWith("deleteWordBackward"); + expect(deletesForWord(1)).toEqual([["deleteWordBackward", 1, ""]]); + // the whole previous word goes too, so the post-navigation length is 0 + expect(deletesForWord(0)).toEqual([["deleteWordBackward", 0, ""]]); + expect(getInput()).toBe(""); + }); + + it("does not regress past the first word", async () => { + replaceConfig({ deleteOnError: "letter_hard", stopOnError: "off" }); + pushWords("hello", "world"); + + await type("x"); + + expect(nav.goToPreviousWord).not.toHaveBeenCalled(); + expect(mockState.activeWordIndex).toBe(0); + expect(deletesForWord(0)).toEqual([["deleteContentBackward", 1, ""]]); + }); + + it("does not regress on a mistake later in the word", async () => { + replaceConfig({ deleteOnError: "letter_hard", stopOnError: "off" }); + pushWords("hello", "world"); + for (const char of "hello ") await type(char); + await type("w"); + + await type("x"); + + expect(nav.goToPreviousWord).not.toHaveBeenCalled(); + expect(mockState.activeWordIndex).toBe(1); + expect(getInput()).toBe(""); + }); + }); + + describe("when it must not fire", () => { + it("stays quiet on a correct character", async () => { + pushWords("hello", "world"); + await type("h"); + + expect(deletesForWord(0)).toEqual([]); + expect(getInput()).toBe("h"); + }); + + it("stays quiet when the config is off", async () => { + replaceConfig({ deleteOnError: "off", stopOnError: "off" }); + pushWords("hello", "world"); + await type("x"); + + expect(deletesForWord(0)).toEqual([]); + expect(getInput()).toBe("x"); + }); + + it("stays quiet when opposite shift already took the char back", async () => { + replaceConfig({ + deleteOnError: "letter", + stopOnError: "off", + oppositeShiftMode: "on", + }); + mockState.correctShiftUsed = false; + pushWords("hello", "world"); + await type("h"); + + // the char was removed by the shift check, so there is nothing to delete + expect(deletesForWord(0)).toEqual([]); + expect(getInput()).toBe(""); + }); + }); + + it("marks its deletions automatic and still counts the mistake", async () => { + pushWords("hello", "world"); + await type("h"); + await type("x"); + + const events = inputEventsForWord(0); + expect(events.map((e) => e.data.automatic)).toEqual([ + undefined, // h + undefined, // x - the user typed it, it is only the deletes that are ours + true, + true, + ]); + // the mistake is still on the record even though the input is gone + const incorrect = events.filter( + (e) => "correct" in e.data && !e.data.correct, + ); + expect(incorrect).toHaveLength(1); + }); +}); diff --git a/frontend/__tests__/input/helpers/fail-or-finish.spec.ts b/frontend/__tests__/input/helpers/fail-or-finish.spec.ts index fb6a8fae14d6..14de4f3dba2c 100644 --- a/frontend/__tests__/input/helpers/fail-or-finish.spec.ts +++ b/frontend/__tests__/input/helpers/fail-or-finish.spec.ts @@ -336,6 +336,7 @@ describe("checkIfFinished", () => { replaceConfig({ quickEnd: false, stopOnError: "off", + deleteOnError: "off", }); // oxlint-disable-next-line typescript/no-unsafe-call (Strings.isSpace as any).mockReturnValue(false); @@ -384,6 +385,31 @@ describe("checkIfFinished", () => { config: { quickEnd: false }, expected: false, }, + { + //the character is taken back, so it must not end the test + desc: "false if quickEnd enabled, lengths match, but stop on error is on", + allWordsTyped: true, + testInputWithData: "asdf", + currentWord: "word", + config: { quickEnd: true, stopOnError: "letter" }, + expected: false, + }, + { + desc: "false if quickEnd enabled, lengths match, but delete on error is on", + allWordsTyped: true, + testInputWithData: "asdf", + currentWord: "word", + config: { quickEnd: true, deleteOnError: "letter" }, + expected: false, + }, + { + desc: "true if quickEnd enabled, lengths match and delete on error is off", + allWordsTyped: true, + testInputWithData: "asdf", + currentWord: "word", + config: { quickEnd: true, deleteOnError: "off" }, + expected: true, + }, { desc: "true if space on the last word", allWordsTyped: true, diff --git a/frontend/__tests__/input/helpers/validation.spec.ts b/frontend/__tests__/input/helpers/validation.spec.ts index d1431b946b35..479077433976 100644 --- a/frontend/__tests__/input/helpers/validation.spec.ts +++ b/frontend/__tests__/input/helpers/validation.spec.ts @@ -164,6 +164,7 @@ describe("shouldGoToNextWord", () => { replaceConfig({ mode: "time", stopOnError: "off", + deleteOnError: "off", strictSpace: false, difficulty: "normal", }); @@ -320,6 +321,43 @@ describe("shouldGoToNextWord", () => { }, expected: true, }, + // Delete on error + { + desc: "stay on incorrect word (deleteOnError letter)", + inputValue: "hel", + targetWord: "hello ", + config: { + stopOnError: "off", + deleteOnError: "letter", + strictSpace: false, + difficulty: "normal", + }, + expected: false, + }, + { + desc: "stay on incorrect word (deleteOnError word)", + inputValue: "hel", + targetWord: "hello ", + config: { + stopOnError: "off", + deleteOnError: "word", + strictSpace: false, + difficulty: "normal", + }, + expected: false, + }, + { + desc: "go to next word on correct word (deleteOnError letter)", + inputValue: "hello", + targetWord: "hello ", + config: { + stopOnError: "off", + deleteOnError: "letter", + strictSpace: false, + difficulty: "normal", + }, + expected: true, + }, ])("$desc", ({ inputValue, targetWord, config, expected }) => { replaceConfig(config as any); expect( diff --git a/frontend/__tests__/test/events/stats.spec.ts b/frontend/__tests__/test/events/stats.spec.ts index 8a089301488b..6cd6caec9301 100644 --- a/frontend/__tests__/test/events/stats.spec.ts +++ b/frontend/__tests__/test/events/stats.spec.ts @@ -60,7 +60,11 @@ import { buildEventLog, __testing, } from "../../../src/ts/test/events/data"; -import { getEventsPerWord } from "../../../src/ts/test/events/helpers"; +import { + findInputValueMismatches, + getEventsForWord, + getEventsPerWord, +} from "../../../src/ts/test/events/helpers"; import { getStartToFirstKeypressMs, getLastKeypressToEndMs, @@ -83,6 +87,7 @@ import { } from "../../../src/ts/test/events/stats"; import type { InputEventData, + InputEventNoMs, KeydownEventData, KeyupEventData, TimerEventData, @@ -1893,4 +1898,196 @@ describe("stats.ts", () => { expect(getCorrectedWordsHistory(buildEventLog())).toEqual(["test "]); }); }); + + // the deleteOnError config deletes input from within the insertText handler; + // these mirror the event sequences it emits (see input/handlers/insert-text) + describe("delete on error", () => { + function inputEventsForWord(wordIndex: number): InputEventNoMs[] { + return getEventsForWord(getAllTestEvents(), wordIndex).filter( + (e): e is InputEventNoMs => e.type === "input", + ); + } + + it("letter mode deletes the incorrect char and the one before it", () => { + pushWords("hello", "world"); + logTestEvent("timer", 1000, timer("start", 0)); + logTestEvent("input", 1100, input({ wordIndex: 0, data: "h" })); + logTestEvent( + "input", + 1110, + input({ wordIndex: 0, data: "e", charIndex: 1 }), + ); + logTestEvent( + "input", + 1120, + input({ wordIndex: 0, data: "x", charIndex: 2, correct: false }), + ); + logTestEvent("input", 1120, { + wordIndex: 0, + charIndex: 3, + inputType: "deleteContentBackward", + automatic: true, + inputValue: "he", + }); + logTestEvent("input", 1120, { + wordIndex: 0, + charIndex: 2, + inputType: "deleteContentBackward", + automatic: true, + inputValue: "h", + }); + logTestEvent("timer", 5000, timer("end", 4)); + + expect(findInputValueMismatches(inputEventsForWord(0))).toEqual([]); + expect(getInputHistory(buildEventLog())[0]).toBe("h"); + // the mistake still counts against accuracy + const acc = getAccuracy(buildEventLog()); + expect(acc.correct).toBe(2); + expect(acc.incorrect).toBe(1); + // and is still visible in the corrected history + expect(getCorrectedWordsHistory(buildEventLog())[0]).toBe("hex"); + }); + + it("letter mode deletes only the incorrect char at the start of a word", () => { + pushWords("hello", "world"); + logTestEvent("timer", 1000, timer("start", 0)); + logTestEvent( + "input", + 1100, + input({ wordIndex: 0, data: "x", correct: false }), + ); + logTestEvent("input", 1100, { + wordIndex: 0, + charIndex: 1, + inputType: "deleteContentBackward", + automatic: true, + inputValue: "", + }); + logTestEvent("timer", 5000, timer("end", 4)); + + expect(findInputValueMismatches(inputEventsForWord(0))).toEqual([]); + expect(getInputHistory(buildEventLog())[0]).toBe(""); + }); + + it("word mode clears the whole word", () => { + pushWords("hello", "world"); + logTestEvent("timer", 1000, timer("start", 0)); + logTestEvent("input", 1100, input({ wordIndex: 0, data: "h" })); + logTestEvent( + "input", + 1110, + input({ wordIndex: 0, data: "e", charIndex: 1 }), + ); + logTestEvent( + "input", + 1120, + input({ wordIndex: 0, data: "x", charIndex: 2, correct: false }), + ); + logTestEvent("input", 1120, { + wordIndex: 0, + charIndex: 3, + inputType: "deleteWordBackward", + automatic: true, + inputValue: "", + }); + logTestEvent("timer", 5000, timer("end", 4)); + + expect(findInputValueMismatches(inputEventsForWord(0))).toEqual([]); + expect(getInputHistory(buildEventLog())[0]).toBe(""); + expect(getCorrectedWordsHistory(buildEventLog())[0]).toBe("hex"); + }); + + it("hard mode regresses to the previous word on a first-char mistake", () => { + pushWords("hello", "world"); + logTestEvent("timer", 1000, timer("start", 0)); + for (const [i, char] of [..."hello"].entries()) { + logTestEvent( + "input", + 1100 + i * 10, + input({ wordIndex: 0, data: char, charIndex: i }), + ); + } + logTestEvent( + "input", + 1150, + input({ wordIndex: 0, data: " ", charIndex: 5, commitsWord: true }), + ); + + mockState.activeWordIndex = 1; + logTestEvent( + "input", + 1200, + input({ wordIndex: 1, data: "x", correct: false }), + ); + // the incorrect char is deleted from the word it was typed in... + logTestEvent("input", 1200, { + wordIndex: 1, + charIndex: 1, + inputType: "deleteContentBackward", + automatic: true, + inputValue: "", + }); + // ...then the regression lands on the previous word, separator removed + mockState.activeWordIndex = 0; + logTestEvent("input", 1200, { + wordIndex: 0, + charIndex: 5, + inputType: "deleteContentBackward", + automatic: true, + inputValue: "hello", + }); + logTestEvent("timer", 5000, timer("end", 4)); + + expect(findInputValueMismatches(inputEventsForWord(0))).toEqual([]); + expect(findInputValueMismatches(inputEventsForWord(1))).toEqual([]); + const history = getInputHistory(buildEventLog()); + expect(history[0]).toBe("hello"); + expect(history[1]).toBe(""); + }); + + it("marks its deletions as automatic, the user's own are not", () => { + pushWords("hello", "world"); + logTestEvent("timer", 1000, timer("start", 0)); + logTestEvent("input", 1100, input({ wordIndex: 0, data: "h" })); + logTestEvent( + "input", + 1110, + input({ wordIndex: 0, data: "x", charIndex: 1, correct: false }), + ); + // the two deletions delete-on-error triggered + logTestEvent("input", 1110, { + wordIndex: 0, + charIndex: 2, + inputType: "deleteContentBackward", + inputValue: "h", + automatic: true, + }); + logTestEvent("input", 1110, { + wordIndex: 0, + charIndex: 1, + inputType: "deleteContentBackward", + inputValue: "", + automatic: true, + }); + // one the user pressed themselves afterwards + logTestEvent("input", 1300, { + wordIndex: 0, + charIndex: 0, + inputType: "deleteContentBackward", + inputValue: "", + }); + logTestEvent("timer", 5000, timer("end", 4)); + + const deletes = inputEventsForWord(0).filter((e) => + e.data.inputType.startsWith("delete"), + ); + expect(deletes.map((e) => e.data.automatic)).toEqual([ + true, + true, + undefined, + ]); + // the flag is informational - it does not change what is derived + expect(getInputHistory(buildEventLog())[0]).toBe(""); + }); + }); }); diff --git a/frontend/src/ts/commandline/commandline-metadata.ts b/frontend/src/ts/commandline/commandline-metadata.ts index 999614654a29..ebb7c16bfbbc 100644 --- a/frontend/src/ts/commandline/commandline-metadata.ts +++ b/frontend/src/ts/commandline/commandline-metadata.ts @@ -311,6 +311,12 @@ export const commandlineConfigMetadata: CommandlineConfigMetadataObject = { options: "fromSchema", }, }, + deleteOnError: { + subgroup: { + options: "fromSchema", + display: (deleteOnError) => deleteOnError.replace(/_/g, " "), + }, + }, confidenceMode: { subgroup: { options: "fromSchema", diff --git a/frontend/src/ts/commandline/lists.ts b/frontend/src/ts/commandline/lists.ts index 326f9cfdfb06..9f591906b98c 100644 --- a/frontend/src/ts/commandline/lists.ts +++ b/frontend/src/ts/commandline/lists.ts @@ -112,6 +112,7 @@ export const commands: CommandsSubgroup = { "strictSpace", "oppositeShiftMode", "stopOnError", + "deleteOnError", "confidenceMode", "quickEnd", "indicateTypos", diff --git a/frontend/src/ts/components/pages/settings/SettingsPage.tsx b/frontend/src/ts/components/pages/settings/SettingsPage.tsx index 6722313494fa..9f5b6cd57fcd 100644 --- a/frontend/src/ts/components/pages/settings/SettingsPage.tsx +++ b/frontend/src/ts/components/pages/settings/SettingsPage.tsx @@ -102,6 +102,7 @@ export function SettingsPage(): JSXElement { + diff --git a/frontend/src/ts/components/pages/test/modes-notice/TestModesNotice.tsx b/frontend/src/ts/components/pages/test/modes-notice/TestModesNotice.tsx index 11b2bae3222a..70a9230ef2e5 100644 --- a/frontend/src/ts/components/pages/test/modes-notice/TestModesNotice.tsx +++ b/frontend/src/ts/components/pages/test/modes-notice/TestModesNotice.tsx @@ -58,6 +58,7 @@ export function TestModesNotice() { + @@ -345,6 +346,19 @@ function StopOnError() { ); } +function DeleteOnError() { + return ( + + ); +} + function Layout() { return ( { + if (value !== "off") { + return { + confidenceMode: "off", + stopOnError: "off", }; } return {}; @@ -527,6 +546,7 @@ export const configMetadata: ConfigMetadataObject = { return { freedomMode: false, stopOnError: "off", + deleteOnError: "off", }; } return {}; diff --git a/frontend/src/ts/constants/default-config.ts b/frontend/src/ts/constants/default-config.ts index 3625eb63dd87..b2a43d49d64c 100644 --- a/frontend/src/ts/constants/default-config.ts +++ b/frontend/src/ts/constants/default-config.ts @@ -52,6 +52,7 @@ const obj: Config = { timerColor: "main", timerOpacity: "1", stopOnError: "off", + deleteOnError: "off", showAllLines: false, keymapMode: "off", keymapStyle: "staggered", diff --git a/frontend/src/ts/input/handlers/before-insert-text.ts b/frontend/src/ts/input/handlers/before-insert-text.ts index 82c9d0823e54..3f5bbe7adc1e 100644 --- a/frontend/src/ts/input/handlers/before-insert-text.ts +++ b/frontend/src/ts/input/handlers/before-insert-text.ts @@ -60,13 +60,17 @@ export function onBeforeInsertText(data: string): boolean { }); //prevent separator from being inserted if input is empty - //allow if strict space is enabled - if ( - isSpace(data) && - inputValue === "" && - Config.difficulty === "normal" && - !Config.strictSpace - ) { + //some conditions may override this + //the hard delete on error variants need the separator to reach onInsertText + //so it can be counted as a mistake and send the user back a word - it can + //never be a mistake in zen, so dont let it through there + const deleteOnErrorIsHard = + Config.mode !== "zen" && + (Config.deleteOnError === "letter_hard" || + Config.deleteOnError === "word_hard"); + const allowFirstSeparator = + Config.strictSpace || Config.difficulty !== "normal" || deleteOnErrorIsHard; + if (isSpace(data) && inputValue === "" && !allowFirstSeparator) { return true; } diff --git a/frontend/src/ts/input/handlers/insert-text.ts b/frontend/src/ts/input/handlers/insert-text.ts index 3dab68fbc7c4..82b4ba637bf8 100644 --- a/frontend/src/ts/input/handlers/insert-text.ts +++ b/frontend/src/ts/input/handlers/insert-text.ts @@ -24,13 +24,14 @@ import { resetIncorrectShiftsInARow, } from "../state"; import { showNoticeNotification } from "../../states/notifications"; -import { goToNextWord } from "../helpers/word-navigation"; +import { goToNextWord, goToPreviousWord } from "../helpers/word-navigation"; import { onBeforeInsertText } from "./before-insert-text"; import { shouldGoToNextWord, isCharCorrect } from "../helpers/validation"; import { getCurrentInput, logTestEvent } from "../../test/events/data"; import { getCommitCharacterType, normalizeData } from "../helpers/util"; import { areAllWordsGenerated } from "../../test/words-generator"; import { getActiveWordIndex, isTestActive } from "../../states/test"; +import { DeleteInputType } from "../helpers/input-type"; const charOverrides = new Map([ ["…", "..."], @@ -55,10 +56,75 @@ type OnInsertTextParams = { isCompositionEnding?: true; // are we on the last character of a multi character input lastInMultiIndex?: boolean; + // true if monkeytype is inserting this itself, not the user + automatic?: true; }; +function logDeleteOnErrorEvent( + inputType: DeleteInputType, + now: number, + charIndex: number, +): void { + logTestEvent("input", now, { + inputType, + wordIndex: getActiveWordIndex(), + charIndex, + inputValue: getInputElementValue().inputValue, + automatic: true, + }); +} + +/** + * Deletes input after an incorrect keypress, based on the deleteOnError config. + * Every deletion is logged as a delete event, because the UI, live stats and + * replay all derive the current input from the event log - editing the input + * element without logging would desync them. + * @param now - Timestamp of the input event that triggered the deletion + */ +function handleDeleteOnError(now: number): void { + const deleteWholeWord = + Config.deleteOnError === "word" || Config.deleteOnError === "word_hard"; + const goBackAWord = + Config.deleteOnError === "letter_hard" || + Config.deleteOnError === "word_hard"; + + //the incorrect character has already been inserted and logged at this point + const inputLength = getCurrentInput().length; + + if (inputLength > 0) { + if (deleteWholeWord) { + setInputElementValue(""); + logDeleteOnErrorEvent("deleteWordBackward", now, inputLength); + } else { + //delete the incorrect character + replaceInputElementLastValueChar(""); + logDeleteOnErrorEvent("deleteContentBackward", now, inputLength); + + //and the one before it, so that a mistake actually costs progress + if (inputLength > 1) { + replaceInputElementLastValueChar(""); + logDeleteOnErrorEvent("deleteContentBackward", now, inputLength - 1); + } + } + } + + //mistake on the first character of the word - the hard modes send you back + if (goBackAWord && inputLength <= 1 && getActiveWordIndex() > 0) { + //pretend its a normal backspace, not insertText + const inputType: DeleteInputType = deleteWholeWord + ? "deleteWordBackward" + : "deleteContentBackward"; + goToPreviousWord(inputType); + logDeleteOnErrorEvent( + inputType, + now, + getInputElementValue().inputValue.length, + ); + } +} + export async function onInsertText(options: OnInsertTextParams): Promise { - const { now, lastInMultiIndex, isCompositionEnding } = options; + const { now, lastInMultiIndex, isCompositionEnding, automatic } = options; const { inputValue } = getInputElementValue(); if (options.data.length > 1) { @@ -215,6 +281,7 @@ export async function onInsertText(options: OnInsertTextParams): Promise { charIndex: testInput.length, isCompositionEnding: isCompositionEnding ? true : undefined, inputStopped: removeLastChar ? true : undefined, + automatic: automatic ? true : undefined, // inputValue is captured from the input element after this event (before goToNextWord clears it). inputValue: inputValueAfterEvent, commitsWord: goingToNextWord ? true : undefined, @@ -224,6 +291,13 @@ export async function onInsertText(options: OnInsertTextParams): Promise { // this needs to be called after event logging WeakSpot.updateScore(data, correct); + // delete on error + // skipped when the input was stopped - nothing was inserted to delete + // before the UI update so it renders the input after the deletion, in one go + if (Config.deleteOnError !== "off" && !correct && !removeLastChar) { + handleDeleteOnError(now); + } + if (lastInMultiOrSingle) { TestUI.afterTestTextInput(correct, visualInputOverride, goingToNextWord); } @@ -254,7 +328,7 @@ export async function onInsertText(options: OnInsertTextParams): Promise { isCurrentCharTab ) { setTimeout(() => { - void emulateInsertText({ data: "\t", now }); + void emulateInsertText({ data: "\t", now, automatic: true }); }, 0); } diff --git a/frontend/src/ts/input/helpers/fail-or-finish.ts b/frontend/src/ts/input/helpers/fail-or-finish.ts index 0257af723324..5d841aa2bea2 100644 --- a/frontend/src/ts/input/helpers/fail-or-finish.ts +++ b/frontend/src/ts/input/helpers/fail-or-finish.ts @@ -96,10 +96,13 @@ export function checkIfFinished(options: { allWordsGenerated, } = options; const wordIsCorrect = testInputWithData === currentWord; + // stop on error and delete on error both take the last character back, so + // quick end must not finish the test on a character that is about to go away const shouldQuickEnd = Config.quickEnd && currentWord.length === testInputWithData.length && - Config.stopOnError === "off"; + Config.stopOnError === "off" && + Config.deleteOnError === "off"; if ( allWordsTyped && allWordsGenerated && diff --git a/frontend/src/ts/input/helpers/validation.ts b/frontend/src/ts/input/helpers/validation.ts index dad7e271a1be..fb56523a56ec 100644 --- a/frontend/src/ts/input/helpers/validation.ts +++ b/frontend/src/ts/input/helpers/validation.ts @@ -76,5 +76,10 @@ export function shouldGoToNextWord(options: { return false; } + //delete on error + if (Config.deleteOnError !== "off" && !correct) { + return false; + } + return true; } diff --git a/frontend/src/ts/test/events/types.ts b/frontend/src/ts/test/events/types.ts index 919f20bf5ca6..53097efea24a 100644 --- a/frontend/src/ts/test/events/types.ts +++ b/frontend/src/ts/test/events/types.ts @@ -92,6 +92,11 @@ type BaseInputEventData = { charIndex: number; wordIndex: number; inputValue: string; + // true when monkeytype produced this input itself instead of the user + // pressing a key - delete on error, code mode auto indentation. There is no + // keydown behind these, and they share the timestamp of the keypress that + // triggered them. + automatic?: true; }; export type InputEventData = diff --git a/frontend/src/ts/test/result.ts b/frontend/src/ts/test/result.ts index d163a15cb5a8..6b626aa72e0e 100644 --- a/frontend/src/ts/test/result.ts +++ b/frontend/src/ts/test/result.ts @@ -808,6 +808,9 @@ function updateTestType(randomQuote: Quote | null): void { if (Config.stopOnError !== "off") { testType += `
stop on ${Config.stopOnError}`; } + if (Config.deleteOnError !== "off") { + testType += `
delete on ${Config.deleteOnError.replace(/_/g, " ")}`; + } qsa("#result .stats .testType .bottom")?.setHtml(testType); } diff --git a/packages/schemas/src/configs.ts b/packages/schemas/src/configs.ts index 36c979dafcde..3cff473cfd5e 100644 --- a/packages/schemas/src/configs.ts +++ b/packages/schemas/src/configs.ts @@ -92,6 +92,15 @@ 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; @@ -428,6 +437,7 @@ export const ConfigSchema = z strictSpace: z.boolean(), oppositeShiftMode: OppositeShiftModeSchema, stopOnError: StopOnErrorSchema, + deleteOnError: DeleteOnErrorSchema, confidenceMode: ConfidenceModeSchema, quickEnd: z.boolean(), indicateTypos: IndicateTyposSchema, From b9edfbebdb30fef2e7e32f9a7b04981742c52b42 Mon Sep 17 00:00:00 2001 From: Miodec Date: Mon, 3 Aug 2026 18:21:07 +0100 Subject: [PATCH 2/2] chore: bump oxc --- backend/package.json | 2 +- frontend/package.json | 2 +- package.json | 4 +- packages/challenges/package.json | 2 +- packages/contracts/package.json | 2 +- packages/funbox/package.json | 2 +- packages/release/package.json | 2 +- packages/schemas/package.json | 2 +- packages/tsup-config/package.json | 2 +- packages/util/package.json | 2 +- pnpm-lock.yaml | 524 +++++++++++++++--------------- 11 files changed, 273 insertions(+), 273 deletions(-) diff --git a/backend/package.json b/backend/package.json index e511719a0290..c28bee3219fe 100644 --- a/backend/package.json +++ b/backend/package.json @@ -81,7 +81,7 @@ "@vitest/coverage-v8": "4.1.5", "concurrently": "8.2.2", "openapi3-ts": "2.0.2", - "oxlint": "1.75.0", + "oxlint": "1.77.0", "oxlint-tsgolint": "7.0.2001", "readline-sync": "1.4.10", "supertest": "7.1.4", diff --git a/frontend/package.json b/frontend/package.json index 9fcd96d2c4d3..9234f3fdf969 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -109,7 +109,7 @@ "madge": "8.0.0", "magic-string": "0.30.17", "normalize.css": "8.0.1", - "oxlint": "1.75.0", + "oxlint": "1.77.0", "oxlint-tsgolint": "7.0.2001", "postcss": "8.5.15", "sass": "1.70.0", diff --git a/package.json b/package.json index f821c8066209..c38cf5fce706 100644 --- a/package.json +++ b/package.json @@ -71,8 +71,8 @@ "knip": "2.19.2", "lint-staged": "13.2.3", "only-allow": "1.2.1", - "oxfmt": "0.60.0", - "oxlint": "1.75.0", + "oxfmt": "0.62.0", + "oxlint": "1.77.0", "oxlint-tsgolint": "7.0.2001", "prettier": "3.7.1", "stylelint": "17.6.0", diff --git a/packages/challenges/package.json b/packages/challenges/package.json index 2cc5edacc5da..01287d02f03f 100644 --- a/packages/challenges/package.json +++ b/packages/challenges/package.json @@ -26,7 +26,7 @@ "@monkeytype/typescript-config": "workspace:*", "@types/node": "24.9.1", "madge": "8.0.0", - "oxlint": "1.75.0", + "oxlint": "1.77.0", "oxlint-tsgolint": "7.0.2001", "tsup": "8.4.0", "typescript": "7.0.2", diff --git a/packages/contracts/package.json b/packages/contracts/package.json index 671dd9164f06..b336997a077c 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -30,7 +30,7 @@ "@monkeytype/typescript-config": "workspace:*", "@types/node": "24.9.1", "madge": "8.0.0", - "oxlint": "1.75.0", + "oxlint": "1.77.0", "oxlint-tsgolint": "7.0.2001", "tsup": "8.4.0", "typescript": "7.0.2", diff --git a/packages/funbox/package.json b/packages/funbox/package.json index f2ff2211e98f..395679707830 100644 --- a/packages/funbox/package.json +++ b/packages/funbox/package.json @@ -26,7 +26,7 @@ "@monkeytype/typescript-config": "workspace:*", "@types/node": "24.9.1", "madge": "8.0.0", - "oxlint": "1.75.0", + "oxlint": "1.77.0", "oxlint-tsgolint": "7.0.2001", "tsup": "8.4.0", "typescript": "7.0.2", diff --git a/packages/release/package.json b/packages/release/package.json index e7b27829179c..eb572cd9acf7 100644 --- a/packages/release/package.json +++ b/packages/release/package.json @@ -20,7 +20,7 @@ }, "devDependencies": { "nodemon": "3.1.14", - "oxlint": "1.75.0", + "oxlint": "1.77.0", "oxlint-tsgolint": "7.0.2001" } } diff --git a/packages/schemas/package.json b/packages/schemas/package.json index 75a15019a34e..b755166bb029 100644 --- a/packages/schemas/package.json +++ b/packages/schemas/package.json @@ -30,7 +30,7 @@ "@monkeytype/typescript-config": "workspace:*", "@types/node": "24.9.1", "madge": "8.0.0", - "oxlint": "1.75.0", + "oxlint": "1.77.0", "oxlint-tsgolint": "7.0.2001", "tsup": "8.4.0", "typescript": "7.0.2", diff --git a/packages/tsup-config/package.json b/packages/tsup-config/package.json index 4b8e976f26de..758f32ff3c43 100644 --- a/packages/tsup-config/package.json +++ b/packages/tsup-config/package.json @@ -18,7 +18,7 @@ "devDependencies": { "@monkeytype/typescript-config": "workspace:*", "@types/node": "24.9.1", - "oxlint": "1.75.0", + "oxlint": "1.77.0", "oxlint-tsgolint": "7.0.2001", "typescript": "7.0.2" }, diff --git a/packages/util/package.json b/packages/util/package.json index 808b0292c874..053a545b86b8 100644 --- a/packages/util/package.json +++ b/packages/util/package.json @@ -21,7 +21,7 @@ "@monkeytype/typescript-config": "workspace:*", "@types/node": "24.9.1", "madge": "8.0.0", - "oxlint": "1.75.0", + "oxlint": "1.77.0", "oxlint-tsgolint": "7.0.2001", "tsup": "8.4.0", "typescript": "7.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 99734dc17bab..d2d592c8bc31 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,11 +45,11 @@ importers: specifier: 1.2.1 version: 1.2.1 oxfmt: - specifier: 0.60.0 - version: 0.60.0 + specifier: 0.62.0 + version: 0.62.0 oxlint: - specifier: 1.75.0 - version: 1.75.0(oxlint-tsgolint@7.0.2001) + specifier: 1.77.0 + version: 1.77.0(oxlint-tsgolint@7.0.2001) oxlint-tsgolint: specifier: 7.0.2001 version: 7.0.2001 @@ -256,8 +256,8 @@ importers: specifier: 2.0.2 version: 2.0.2 oxlint: - specifier: 1.75.0 - version: 1.75.0(oxlint-tsgolint@7.0.2001) + specifier: 1.77.0 + version: 1.77.0(oxlint-tsgolint@7.0.2001) oxlint-tsgolint: specifier: 7.0.2001 version: 7.0.2001 @@ -530,8 +530,8 @@ importers: specifier: 8.0.1 version: 8.0.1 oxlint: - specifier: 1.75.0 - version: 1.75.0(oxlint-tsgolint@7.0.2001) + specifier: 1.77.0 + version: 1.77.0(oxlint-tsgolint@7.0.2001) oxlint-tsgolint: specifier: 7.0.2001 version: 7.0.2001 @@ -664,8 +664,8 @@ importers: specifier: 8.0.0 version: 8.0.0(typescript@7.0.2) oxlint: - specifier: 1.75.0 - version: 1.75.0(oxlint-tsgolint@7.0.2001) + specifier: 1.77.0 + version: 1.77.0(oxlint-tsgolint@7.0.2001) oxlint-tsgolint: specifier: 7.0.2001 version: 7.0.2001 @@ -677,7 +677,7 @@ importers: version: 7.0.2 vitest: specifier: 4.1.0 - version: 4.1.0(@types/node@24.9.1)(happy-dom@20.8.9)(jsdom@27.4.0)(vite@8.0.5(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.0)(@types/node@24.9.1)(esbuild@0.27.7)(jiti@2.7.0)(sass@1.98.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.0(@types/node@24.9.1)(happy-dom@20.8.9)(jsdom@27.4.0)(vite@8.0.5(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.0)(@types/node@24.9.1)(esbuild@0.25.0)(jiti@2.7.0)(sass@1.98.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.8.3)) packages/contracts: dependencies: @@ -704,8 +704,8 @@ importers: specifier: 8.0.0 version: 8.0.0(typescript@7.0.2) oxlint: - specifier: 1.75.0 - version: 1.75.0(oxlint-tsgolint@7.0.2001) + specifier: 1.77.0 + version: 1.77.0(oxlint-tsgolint@7.0.2001) oxlint-tsgolint: specifier: 7.0.2001 version: 7.0.2001 @@ -717,7 +717,7 @@ importers: version: 7.0.2 vitest: specifier: 4.1.0 - version: 4.1.0(@types/node@24.9.1)(happy-dom@20.8.9)(jsdom@27.4.0)(vite@8.0.5(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.0)(@types/node@24.9.1)(esbuild@0.25.0)(jiti@2.7.0)(sass@1.98.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.8.3)) + version: 4.1.0(@types/node@24.9.1)(happy-dom@20.8.9)(jsdom@27.4.0)(vite@8.0.5(@emnapi/core@1.9.0)(@emnapi/runtime@1.9.0)(@types/node@24.9.1)(esbuild@0.27.7)(jiti@2.7.0)(sass@1.98.0)(terser@5.49.0)(tsx@4.21.0)(yaml@2.8.3)) packages/funbox: dependencies: @@ -741,8 +741,8 @@ importers: specifier: 8.0.0 version: 8.0.0(typescript@7.0.2) oxlint: - specifier: 1.75.0 - version: 1.75.0(oxlint-tsgolint@7.0.2001) + specifier: 1.77.0 + version: 1.77.0(oxlint-tsgolint@7.0.2001) oxlint-tsgolint: specifier: 7.0.2001 version: 7.0.2001 @@ -778,8 +778,8 @@ importers: specifier: 3.1.14 version: 3.1.14 oxlint: - specifier: 1.75.0 - version: 1.75.0(oxlint-tsgolint@7.0.2001) + specifier: 1.77.0 + version: 1.77.0(oxlint-tsgolint@7.0.2001) oxlint-tsgolint: specifier: 7.0.2001 version: 7.0.2001 @@ -806,8 +806,8 @@ importers: specifier: 8.0.0 version: 8.0.0(typescript@7.0.2) oxlint: - specifier: 1.75.0 - version: 1.75.0(oxlint-tsgolint@7.0.2001) + specifier: 1.77.0 + version: 1.77.0(oxlint-tsgolint@7.0.2001) oxlint-tsgolint: specifier: 7.0.2001 version: 7.0.2001 @@ -834,8 +834,8 @@ importers: specifier: 24.9.1 version: 24.9.1 oxlint: - specifier: 1.75.0 - version: 1.75.0(oxlint-tsgolint@7.0.2001) + specifier: 1.77.0 + version: 1.77.0(oxlint-tsgolint@7.0.2001) oxlint-tsgolint: specifier: 7.0.2001 version: 7.0.2001 @@ -860,8 +860,8 @@ importers: specifier: 8.0.0 version: 8.0.0(typescript@7.0.2) oxlint: - specifier: 1.75.0 - version: 1.75.0(oxlint-tsgolint@7.0.2001) + specifier: 1.77.0 + version: 1.77.0(oxlint-tsgolint@7.0.2001) oxlint-tsgolint: specifier: 7.0.2001 version: 7.0.2001 @@ -966,8 +966,8 @@ packages: resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} engines: {node: '>=6.9.0'} - '@babel/generator@7.29.7': - resolution: {integrity: sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==} + '@babel/generator@7.29.8': + resolution: {integrity: sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==} engines: {node: '>=6.9.0'} '@babel/helper-annotate-as-pure@7.29.7': @@ -1118,8 +1118,8 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - '@babel/parser@7.29.7': - resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} + '@babel/parser@7.29.8': + resolution: {integrity: sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==} engines: {node: '>=6.0.0'} hasBin: true @@ -1345,8 +1345,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-systemjs@7.29.7': - resolution: {integrity: sha512-TM2ZcQLoG2/y4HODiStCo10DibYhWhGWAwVv+EQKmG/7GFl0N+AAmUiXOMKM+aiJ9XBJ9AHVZBvTzMnJ2sM3cQ==} + '@babel/plugin-transform-modules-systemjs@7.29.8': + resolution: {integrity: sha512-6iSnEK0zlkLKU4heofK/AdmRD4e2SHVpJMtrwnTCzhnaM98ria4rTrOXBBi45BTTYnJtO8txnPsX4fChYXkmeA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1429,8 +1429,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-regenerator@7.29.7': - resolution: {integrity: sha512-rNNFV0DBAJp988xW2DOntfDoYn1eR8GGF5AT5vYc+rjyfaQkM242c9tZUHHPe7KYaiJizXPWhQTzzdbXySyhBw==} + '@babel/plugin-transform-regenerator@7.29.8': + resolution: {integrity: sha512-0UpIXPtdDtMXfnV2OJAVMLpj3H/92vmkA6lpSRakmycJvj3VUy6Xs1dM8tXRugupykr5WB+LpiVl0J8LMVg2mg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1453,8 +1453,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-spread@7.29.7': - resolution: {integrity: sha512-/u5K1QWada7tbYNqTjMh96718g9NTwh9tfPJMsSmVsQwGT447FskV+KcfeXkXq2GWki4EM/MuTdmBec+hOuVTQ==} + '@babel/plugin-transform-spread@7.29.8': + resolution: {integrity: sha512-4S9ksMGVWUshvgK0mKfvZky7leuG5/uoFVwMpAomJ8bMoDJiNHRVmc1EglwW/CmGVSqqWpEbXm9FmbRit22qoA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -1552,8 +1552,8 @@ packages: resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.29.7': - resolution: {integrity: sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==} + '@babel/traverse@7.29.8': + resolution: {integrity: sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==} engines: {node: '>=6.9.0'} '@babel/types@7.28.5': @@ -1568,8 +1568,8 @@ packages: resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} - '@babel/types@7.29.7': - resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} + '@babel/types@7.29.8': + resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==} engines: {node: '>=6.9.0'} '@balena/dockerignore@1.0.2': @@ -3223,116 +3223,116 @@ packages: '@oxc-project/types@0.122.0': resolution: {integrity: sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA==} - '@oxfmt/binding-android-arm-eabi@0.60.0': - resolution: {integrity: sha512-1q4q4Jc8FlOMVojEisyFAVyl8h1yawNv6phjgmhGVEDeyeOdsSnSr9x0+D4mOnEKvpO5L4mxKZ/DP9X6U3A/Mw==} + '@oxfmt/binding-android-arm-eabi@0.62.0': + resolution: {integrity: sha512-pdsv0C4gPjJ8H1+sd8u0BDx+yLACTL+rgeMIOL1ln4ihSnhw8CWXtYWgvcSkyTfgGBIzFKab+d8rx9Xl4en/Kw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxfmt/binding-android-arm64@0.60.0': - resolution: {integrity: sha512-tD41I6nCt9k8SQXft0CSjjU9jg6SwG7uMu7PxodSEHXl+GDW0868oy6tTtoJkyUze8YKFgTpz/k5LuPUnFiGLw==} + '@oxfmt/binding-android-arm64@0.62.0': + resolution: {integrity: sha512-WC3YQ7uS/KtDrjmqwBviwFKe9qeoi+eXx8aX1z/ffG23Md75myjrJaQqTuJvdOLPoa4EYTjDWH0dHXfwulCVog==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxfmt/binding-darwin-arm64@0.60.0': - resolution: {integrity: sha512-TTpzPug96Zxdyb46KvTyIUQDdsqbumXh2TKG9C23PCT0kF7JkW56Z/quPuG9rqOFKQIi1gpRNZ7DX18LwxXPnw==} + '@oxfmt/binding-darwin-arm64@0.62.0': + resolution: {integrity: sha512-GM8Yf3LjjaR1I8PD0SfeoIlwhsh9GvSF+cQ8sf624Yxnjsyumn95aFzYfKJVefblfDIiOAnZ7QVm2sa21Er/0Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxfmt/binding-darwin-x64@0.60.0': - resolution: {integrity: sha512-CnOoWgQ7L+JL/YQaRJ+NyATciSfcftncm7y3kqyte1cGtFEGnStaCd1TAyrinkfQ7nRBfHrTs1/vTwUJr3WF2Q==} + '@oxfmt/binding-darwin-x64@0.62.0': + resolution: {integrity: sha512-d5THp7F8bCxLqNogEXDORRsQD6dosf3EyFtnXfBer6v+8tGdcWIjoDX9WaXrrF/26zOmL8qHpPTKCEvpBDmZkQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxfmt/binding-freebsd-x64@0.60.0': - resolution: {integrity: sha512-ychJo7S3hZxdO6eDZ9zM6F2lM9fpJS3EKS5CAUSWyprdLYxTu4gbaUKV/VBPTcMJwQa2Bpo+643y3OJ537pihA==} + '@oxfmt/binding-freebsd-x64@0.62.0': + resolution: {integrity: sha512-1DnrtXGZooOZ0fHgAXZUaDQzBVh1CM2MNW4oBXyQ2aWKvCHjyljvT9fgBkOM0fEOb96X5eqtcfJ0YUVt9jj66g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxfmt/binding-linux-arm-gnueabihf@0.60.0': - resolution: {integrity: sha512-36IH5o55T2Fx7E0feDttt+mifxN6yk9pWv4KfhAIsP0dFnUq27331OwbpOsZdoXF9soOLWm7mQUz5+UUmyec4g==} + '@oxfmt/binding-linux-arm-gnueabihf@0.62.0': + resolution: {integrity: sha512-4pQDHOYRH+Huqe0StIaWyvk2CVl/aTaqSrbZpA3/pLS2xH24ME7lBgYprhQF2fRkHBzhGGGKliwxFsDdHwx59g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxfmt/binding-linux-arm-musleabihf@0.60.0': - resolution: {integrity: sha512-G1Ve7lAa6sFBolVI2LWHfEAqy0YKh4vnioH8uYO9kAEdgM7mR40IksIx9/Zk4+vbYew/sGa4J9Q4tZ3n9gXDHA==} + '@oxfmt/binding-linux-arm-musleabihf@0.62.0': + resolution: {integrity: sha512-X0jAaZJFMCVKhB6YyWVTQ/wN2DLsBcZKSMqTS76bF6riT+XZdtg2FPEdjDvdVbunO9cG+tWiVaEs4Zs38lxYog==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxfmt/binding-linux-arm64-gnu@0.60.0': - resolution: {integrity: sha512-LTQdRBf6uzj/h7Xk6lKzbGD2hrF/fK4YI9LIN1c0509tPUn8wRa3mCmrFQpEWJPLYGFrLFFMTYW1Ljj6VqW2Hw==} + '@oxfmt/binding-linux-arm64-gnu@0.62.0': + resolution: {integrity: sha512-682Z8T5s8T5ATArYtsejKvbIfd8LEAXyyDkKkoZVq8HND7Vx8TYLlrDjDSeYfodMeVwHOgkj13lJYR8cj6vUSg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - '@oxfmt/binding-linux-arm64-musl@0.60.0': - resolution: {integrity: sha512-2JMo3XPxMPx3hiqddSZYyaH+fKJm6cz0u8n1naYjP/CdOQOZW34i8lKBUfmbWiuFvd6KoYXLmhAyBuvojsYS7Q==} + '@oxfmt/binding-linux-arm64-musl@0.62.0': + resolution: {integrity: sha512-lk25fAl7KWaLWVJcW0CHEXB7QlQZtx5eDkjpaGMK0hzXTjUe0Wmlu8IKuFHoviSOcEJedRTs4VE/506VqGxGew==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - '@oxfmt/binding-linux-ppc64-gnu@0.60.0': - resolution: {integrity: sha512-L3C+nBD13lr306tr/PjM3RMll+BVqgFrIgUyoeHuai5oueJrRLgO3j+GO5/Cbhtkf5PSlHYTI1JY7iqBd1qa6A==} + '@oxfmt/binding-linux-ppc64-gnu@0.62.0': + resolution: {integrity: sha512-SFyNqHQLwySceWNLhiSldx7wPXRAzP0L0WcW9GegP3uWrpZGJiZlQO85NbHAFPEfxR9PhZ9qSnZryEh7+v+4Gw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] - '@oxfmt/binding-linux-riscv64-gnu@0.60.0': - resolution: {integrity: sha512-M4MsmvqlxFiPtSRGyBYQSZxchEf463AOyd+Dh4/9xDpjWBsRtDUTDMFN5EdHinjVK1/eDJQ8MLpcYjpYayaCnA==} + '@oxfmt/binding-linux-riscv64-gnu@0.62.0': + resolution: {integrity: sha512-KYj55C1ywJfHo6+aKDuEmUtVEdJALsC5GwayDGsI6FGz2GxFqNr/mA8nxVsNbJzm7sE5MRqTQ9ziImSzhYXysA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] - '@oxfmt/binding-linux-riscv64-musl@0.60.0': - resolution: {integrity: sha512-OH+9UskYuxRB+GxqdGkVN8f5UpwhqG8YscNo1wl8+KJ62cd7wZdGga6iGLJIf8kibF1WBwvlfDUx3cez/VXwFg==} + '@oxfmt/binding-linux-riscv64-musl@0.62.0': + resolution: {integrity: sha512-BhZDNo5GOU5nC378RhD0/XpvaEBHsH3HLgJp8YZX3A0InC7oivzA63HsRmiXFLtLSHAstEVrDf6fbC7Rs8Jh/A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] - '@oxfmt/binding-linux-s390x-gnu@0.60.0': - resolution: {integrity: sha512-y7AAFutt9wFWBFOAn6+BHaV39usZmcr3YYH2385f+NHgPNpIF9HpqKp0jgUxPaUOCyG3oaX5VhJduL1Nw164rw==} + '@oxfmt/binding-linux-s390x-gnu@0.62.0': + resolution: {integrity: sha512-UyAFmyHkgSgUJ/wOM4p3U8AC2yAFvRH5PNBs7TnK0fObTT/XSWcdr/lAzPSWaekHaZFaMeFZyk9n93Joq3J93A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] - '@oxfmt/binding-linux-x64-gnu@0.60.0': - resolution: {integrity: sha512-yKZ9+CXAI+1RO5nH/4Z/9M6DAsfOzd5bw/gtWk81KB4mpalMaRRSXfouc5/tHxazDmBek55HNPepNYBgaCew0Q==} + '@oxfmt/binding-linux-x64-gnu@0.62.0': + resolution: {integrity: sha512-1iYMP0leytWazFubD/WnINJuIrzRPuoL1aWEJdlGezEzDbTxcd29R4r8IUzP2oWeKst5V02uMJgR2NILlPlG6w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - '@oxfmt/binding-linux-x64-musl@0.60.0': - resolution: {integrity: sha512-bCUGaF6hJOYnQzLJdHLZbvGsOd5oSvGAyJhPAKum2uyLYUuXmP8vqg690DWi2hqcnIoYpqSqCrjzE5aiUAgwQg==} + '@oxfmt/binding-linux-x64-musl@0.62.0': + resolution: {integrity: sha512-4rA/URtJSTVNVAQz6Q8wf7SaRvOXVy+TizriT9hs/Y1XhLR/R+92uWKRQG8yFWRAIEBbFHJ6WevQcl/G9SXEfw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - '@oxfmt/binding-openharmony-arm64@0.60.0': - resolution: {integrity: sha512-GrUeZOvzP30ExxfCuQiyofuUGI+OmvAgFwOO5w5p9mGPlxcyuqI+6Sy9fAKFFfLQrqKYWFgc5sYA2Unj/29nPg==} + '@oxfmt/binding-openharmony-arm64@0.62.0': + resolution: {integrity: sha512-mSZuFHU2ar1KLUjXpI2QBQcJ1VsOB3mOCgQXuXCpKs19dgh4u+OaovNfrWDfiJb+ihJ2+f7YFcaO9bS2dlTCXA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxfmt/binding-win32-arm64-msvc@0.60.0': - resolution: {integrity: sha512-WD4Q954kUl2TDJV/6q7UnE2rlKk047kXLJsr4bJ2mXRaAqNXcmV3nwKUsGCc3mz/jYDBnXtJEaBErJEybK8iQQ==} + '@oxfmt/binding-win32-arm64-msvc@0.62.0': + resolution: {integrity: sha512-OfwuhkcjDlqC4EgDojtiV9mzpLqeB9KqTOWPOjLEYBVdDCVSxqW3qzp/xcIxsbtI0UgGCnKvAqYKyY25kf5JZw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxfmt/binding-win32-ia32-msvc@0.60.0': - resolution: {integrity: sha512-HqDekjr8JXzVDUP1YthDZ1Y3CBEcuZT4WX3B+1kaxj8CvZA8Y2YhcEsXqoSop3tVsgjACxjnFQFDkBo0r/jq1Q==} + '@oxfmt/binding-win32-ia32-msvc@0.62.0': + resolution: {integrity: sha512-P9uDDNFRzghO3X8QAzhkjKhK7JvtABsVn8UYtFX7uor12IAnwNt8nNIctvfWj1JkQU/kE+fmLRPiw7XlrIHsZw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxfmt/binding-win32-x64-msvc@0.60.0': - resolution: {integrity: sha512-tz78yhmGPKboTMHCHSaUqXK8JrmoSejgDcWeqAtg2s07ZGKQ3rH5Jn8NuXPGNG33CDbY2e9NoQWXIVEmKO21Rw==} + '@oxfmt/binding-win32-x64-msvc@0.62.0': + resolution: {integrity: sha512-dlI5SY7XYQCiCBafntWagCR6HcAJB/NpsLtdlPx8x08+Osz8Ok1HHz1GZuusegCe/VoJ6pAnF5a4pd5OZAq7qQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -3367,116 +3367,116 @@ packages: cpu: [x64] os: [win32] - '@oxlint/binding-android-arm-eabi@1.75.0': - resolution: {integrity: sha512-lutovtFzJqlRaqpZrCqSSGaHZzl9nIxxpjLzhSRLunN6dCLylj0uzlCyQGaQDIys7rrv8kVXiFO+R4Zpn0bX7g==} + '@oxlint/binding-android-arm-eabi@1.77.0': + resolution: {integrity: sha512-E06sKWS6PiI6HRxS1wyQg22HvApt01hI7fV+T3wUk3OSbaaP4a3hYGY/MIQDmASqCiRjBdpRQYkgMkqH82cWmQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@oxlint/binding-android-arm64@1.75.0': - resolution: {integrity: sha512-hXI0hDgHkw4w5nfru72aG7y+2iQJmC4waH/KV6H/hbgA6yAP5jYNx0P9yug15Hs0tWl/+mda3Jjn/2gmDT48tw==} + '@oxlint/binding-android-arm64@1.77.0': + resolution: {integrity: sha512-NvsKz0KZxTp9cYWPLf+FXaSZwB3oO3peAjtukpOMBgse2vhQSoIIVqeO1yR0lEo/UcdZIDL18uq+kL0LzQ0ytA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@oxlint/binding-darwin-arm64@1.75.0': - resolution: {integrity: sha512-D91BWbK/dMYfCcrghspPIuKs2D9LF4Z/OabVSQjw1AO6PWxArD7teDA48bm0ySFqWDaPVqmQRl5GMWNglTXyrQ==} + '@oxlint/binding-darwin-arm64@1.77.0': + resolution: {integrity: sha512-bgjTn6nW4bQCFBvSvuHCpDD+sONvmpo4lGI4PxzMt1quBA+xYxhczk6RiCn3GZ9gY8uhaBbwhj9MdKGfu6T9DA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@oxlint/binding-darwin-x64@1.75.0': - resolution: {integrity: sha512-02mpwzf12BonZ6PT0TuQoomvEh2kVl2WGBIKWezCyToIS+rYkQZ6GXnARBAl9A4Ovm2V+Xe7M4KretyqmmcnJQ==} + '@oxlint/binding-darwin-x64@1.77.0': + resolution: {integrity: sha512-aotaIttH1R6j1Rwhx0M0htgeZyGtVQqYNTVEYMN/UcgHPquGA6kmk9OyuDc3a2GKUQBC+3C3GVQCcrRPMYqAFA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@oxlint/binding-freebsd-x64@1.75.0': - resolution: {integrity: sha512-qZJgLnDaBsiL5YESx2t/TZ8eXkL9fEkKoXEdzegROhlz9A0lgyGnZ0dAzJrh7LJAHQl2K9RdRueN2s/9N7+odg==} + '@oxlint/binding-freebsd-x64@1.77.0': + resolution: {integrity: sha512-nNx/wta7ksRAdYvq+l4AWjXkLxEXHALhENxjj2cYbQAIR4ybaA5L+hCbE63HOmft5czQ6ks+hb8vmEAnn7YGPg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@oxlint/binding-linux-arm-gnueabihf@1.75.0': - resolution: {integrity: sha512-7XlaWA5BJD3XpCfrEqjEe6Zseeb14S7QGa304XfwKignRaKQ+eIj775BQ7nIslggWickl4IsPUFqJ+/gAyNHVg==} + '@oxlint/binding-linux-arm-gnueabihf@1.77.0': + resolution: {integrity: sha512-tMLLjM7xXtzXisVCzkOTXNCy9bZVId2wteNwjohlFDR/jY6WagpEDA1c1wu4xRc20Hojaxj+V6DSR7gbKxijWA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm-musleabihf@1.75.0': - resolution: {integrity: sha512-av6Tpv8yrcMMMOadOqENBhlsLRcGFXXwoQ0hzHhsmS9FJ4Wioy8we427GbcMe2XTxmL2e60T67H1Dyr3up+tAA==} + '@oxlint/binding-linux-arm-musleabihf@1.77.0': + resolution: {integrity: sha512-MiAFDFaqR0tmHTAyo0YDcZ5hyLREdYw/RQhc2R3cbT+8O3tB+zqPM2th9TTQ+Uo3jn/embS+DO+HyX9ztCPkOQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@oxlint/binding-linux-arm64-gnu@1.75.0': - resolution: {integrity: sha512-WcUhd8fHT5plrA14lANevl+hOl815mVI5t2hU21oFWrZKFXIVV/Sr4rWQV0NzSvzBupbMLNc5ErEA6Ehxh5jMg==} + '@oxlint/binding-linux-arm64-gnu@1.77.0': + resolution: {integrity: sha512-/xqQ3B16i1T4cyt/9Mn+4CpzhUXoBXp7kVpIwzOXNFLj5JmK1bIjsbSnX296Gg8A/o7oDtKWikFgBx0SLwztkw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - '@oxlint/binding-linux-arm64-musl@1.75.0': - resolution: {integrity: sha512-UWzp5wRHFe/ESO3+eEaxXsTkYTGLYjnTsi/I5neEacXSItQ6WNleapfOAeA4x2b8nyhJ4uQxqvtv9pHv8kWJtQ==} + '@oxlint/binding-linux-arm64-musl@1.77.0': + resolution: {integrity: sha512-LSbwuRKiNCenPDcbARqAZ5RfBy7gmj7vOvfJRLeCDU3gFtSxWbhv/+VTlaUqzUhNj1gFLHB8h7ALnxa/Az6z6g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - '@oxlint/binding-linux-ppc64-gnu@1.75.0': - resolution: {integrity: sha512-XEVRwGMLKCUKrvhLAz4F6AIh8MJrQVdSZtAmPpRZt9tGPsUnamPOcl3dS/ZQzJnar/Ymgc//+xho0L60Emzuxg==} + '@oxlint/binding-linux-ppc64-gnu@1.77.0': + resolution: {integrity: sha512-QWdcH31mXEUe5Nq1s0CfCpceaKjIo9uZtwDjAuL681g1axf+5x8xrg/eXWaw//4NCxYZ4V4e5Hu5tvdR+pTBlg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] - '@oxlint/binding-linux-riscv64-gnu@1.75.0': - resolution: {integrity: sha512-mAG4DUXqfLC8cTjMD2kt3jDmVzFREYtDyeLNdLdsCcBc4Zbl2EMuiFektGBilQwkNjYnMvCqJs55U+Hyb+b+jw==} + '@oxlint/binding-linux-riscv64-gnu@1.77.0': + resolution: {integrity: sha512-GnOfYgJxbcElOiPZaDFDl406ONddwvOWk2jvAAAEjwAl4GofNoHF+/HHUIBYa6bFCArlcGPi0XjC4cU1pkgF/Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] - '@oxlint/binding-linux-riscv64-musl@1.75.0': - resolution: {integrity: sha512-95hrAvriAlI+pekSomTFIn0+bawMDlDwTNVmdjsFusTHyL2JWh7TWvRNG/Lkim72uN8OiCcO9wcaC6omLP5E3w==} + '@oxlint/binding-linux-riscv64-musl@1.77.0': + resolution: {integrity: sha512-AyEMTUCf0xY+hHF+IxqXFQIX0yQOIR8ykpY0lJNOw9xYqOzUX8dyZfRvlG0RfXwuQn2eonf/8NrMmDSZJjdqsA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] - '@oxlint/binding-linux-s390x-gnu@1.75.0': - resolution: {integrity: sha512-4b6f2+FrtruAESrCqIKcrarzfrSx+wk2QNcp+RT91/Prc+pMQMAfyZ1rG1c3tFQNl8Bc616tx40uNXyxNBRPbQ==} + '@oxlint/binding-linux-s390x-gnu@1.77.0': + resolution: {integrity: sha512-sPLzEcNvxd/oyVQ5oZo92CiHkFkpBeRop13E/P3TPY+hZfXHKCOWKI70TE2RYwMKFJDc20EMjH16L7NZICtKTw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] - '@oxlint/binding-linux-x64-gnu@1.75.0': - resolution: {integrity: sha512-nshAhrUvXFUWOvqQ2soIw7HFNWvpvEV4o0cYSqPtzLiPF5gKyYTDOOTJ6Rn8g8K/iGvPIrbDA4v8+5MvnjJrrg==} + '@oxlint/binding-linux-x64-gnu@1.77.0': + resolution: {integrity: sha512-1Oh2ssH2L7lwyvkdSqaMUfsGfwU2Wfvew+obBUYjRVqhpBcUpwnsPSEr1IzVi9XqkuY10geiLsNKecqaZC34Dw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - '@oxlint/binding-linux-x64-musl@1.75.0': - resolution: {integrity: sha512-e4jNxLKnxLC6sYBQRxrI2pgIIxnmMtF8U/VwNYcjTT/CLS+spH624cYVnj07bTKwaEWT37/e025isOs6j/0xqA==} + '@oxlint/binding-linux-x64-musl@1.77.0': + resolution: {integrity: sha512-0j/2wRgNGO+Qj/M1uu/p57h/hFTTWWcfie0ufkbabeus2s5+/QqkCflnMOwLLN5m2GsNeWp4xdl4cPa4n7QCOQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - '@oxlint/binding-openharmony-arm64@1.75.0': - resolution: {integrity: sha512-hZ2lH+1qLf/DiEP9UWuQTK2JWj/BgvMB4jhIV4SmNU1wfEiYYX4TynQyAZXx0j9X4qRYizAL042SKaV+8ynh4w==} + '@oxlint/binding-openharmony-arm64@1.77.0': + resolution: {integrity: sha512-BJ/j54qS0usEnyDkLYURMj2iiD9h5Cyy+ppzeMSXBGRXaGRNWnj1Mw14NqWMR5E/PzdgB30OOCCzLzbRoduafw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@oxlint/binding-win32-arm64-msvc@1.75.0': - resolution: {integrity: sha512-Ilj6PNzGDS3bCU0MSJH7Msh0NhH+T/mRp2shwg+q+GHeVlPwP5LEboW96aW+3kVKFk6zYZy1Xi5pZkqZh6X8KQ==} + '@oxlint/binding-win32-arm64-msvc@1.77.0': + resolution: {integrity: sha512-Yh8w+g2Lpx7StrvtYkoz9JJvXjB9wxgFChFNb85nrXm/wj/XTwGWS1hve9+900HL7llrntYB3YP+y32E3tRqzA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@oxlint/binding-win32-ia32-msvc@1.75.0': - resolution: {integrity: sha512-QVit2nOEOiPhkmsrksPSkoGCdnZRNkspt8fwoYyP09te1VEbnSj4LAxua4rc8FKTmWkySVe05j8iz9GXYfF1AQ==} + '@oxlint/binding-win32-ia32-msvc@1.77.0': + resolution: {integrity: sha512-zja5b7+6a7UsRFgAQSrnax5vrzliEyNPLCjfXONu/vTWswaIVZGFajJZptaeRvPE4LghtFdAzVFlexTm7MVTGA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ia32] os: [win32] - '@oxlint/binding-win32-x64-msvc@1.75.0': - resolution: {integrity: sha512-DSxnNkBUAYARPwJtR12Ig3deWr8w0H997xP6jy33i+e0SyYJw8FKuz4+cZtpmPEhQmvlPJE3X/2vNxDmLkd/rA==} + '@oxlint/binding-win32-x64-msvc@1.77.0': + resolution: {integrity: sha512-+teyvPDZ2RjUvo+SuCqS/UhaJl1QtdW5fWT5NJTV61V5MIuIS90Db9LixmtEGvXixyttiK62P96MSu3UlpviBw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -5459,8 +5459,8 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - acorn@8.17.0: - resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} + acorn@8.18.0: + resolution: {integrity: sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==} engines: {node: '>=0.4.0'} hasBin: true @@ -5782,8 +5782,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.11.0: - resolution: {integrity: sha512-oCu2wfipvX3AePSgmOuKkIywOu+8n9psz7hXYmk56ghpu3+7KzNIBopaOs4c9BrtdnTtW30unG9GTfHo7EwERQ==} + baseline-browser-mapping@2.11.12: + resolution: {integrity: sha512-r7WnVImvVCeFpf2DOXfy41aPWzeNg3H/A2X4dKmy1QL0MSyyk/e7z8ihJ3N6Nn2PsdhkVlqnEfnUE4a05P2aTA==} engines: {node: '>=6.0.0'} hasBin: true @@ -5863,8 +5863,8 @@ packages: brace-expansion@2.0.2: resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} - brace-expansion@2.1.2: - resolution: {integrity: sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==} + brace-expansion@2.1.4: + resolution: {integrity: sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==} brace-expansion@5.0.4: resolution: {integrity: sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==} @@ -6857,8 +6857,8 @@ packages: electron-to-chromium@1.5.267: resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} - electron-to-chromium@1.5.395: - resolution: {integrity: sha512-7zt9Aw+SrmxLWLN0zhaTWZQiCdryLVrYTq5R7iZakLvi2UQPYMMsROYV/2qVCzMeCiSXHwKOU+sZ4zOVVlrtKA==} + electron-to-chromium@1.5.399: + resolution: {integrity: sha512-lEcqhErbHjXRvd41rnWLpzbyU/IXfIYo7QwaFWmxGeLiLyY2TBCdHnWY88vB+p3ubnihRypDm66panXl7TylLA==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -7187,8 +7187,8 @@ packages: fast-safe-stringify@2.1.1: resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} - fast-uri@3.1.4: - resolution: {integrity: sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==} + fast-uri@3.1.5: + resolution: {integrity: sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==} fast-url-parser@1.1.3: resolution: {integrity: sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==} @@ -9274,8 +9274,8 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - nanoid@3.3.16: - resolution: {integrity: sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==} + nanoid@3.3.17: + resolution: {integrity: sha512-xQLf0A3HOMlgHq0n247/LRuAOYmB7dXJ/DvAxGvsSBij45XtBSmQycu+F8ODbHwns/XyFZagyL1+J0Offw1E0g==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true @@ -9540,8 +9540,8 @@ packages: resolution: {integrity: sha512-19YVAg7T+WTrxggPukVq7DjTv6+PJ867TmhCvBsYwmbFCsZd344rq2Ld1p0wo8f8Qrrhgp82c6FJRqdXWtSEhg==} engines: {node: '>= 0.4'} - oxfmt@0.60.0: - resolution: {integrity: sha512-fViX6i+gJuZWY+jI/fnR6WRbRj70GZ9RlCd30MygJrHTUNc4DxvKHWw8vBjMjffv3PgU5qWDR0AzmojQByqaZA==} + oxfmt@0.62.0: + resolution: {integrity: sha512-vxgGHTmnDU9j4CX7dDBLzxgmHxfda/yPcgJkGCMUSCwRmz+euo/V08xXLNgXTeqAB9Fhf3Pe2nO1RNKLCVgphQ==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -9557,8 +9557,8 @@ packages: resolution: {integrity: sha512-KjK/XLcXr1DSyonKhsuFqJRiuKqcyG9j3LJ8nkOsrLzGvodBPqzHOKauy10asLMDI0sUpvb+1sxlzff3udZvfg==} hasBin: true - oxlint@1.75.0: - resolution: {integrity: sha512-m9WzjRcRYA/uqIZDa9tclrieoPJ/ln1QYTKdFx6NUOs8uY5DiHlIwRQoCrHT6OM6O3ww3l2skY5gO7G7ZphE7g==} + oxlint@1.77.0: + resolution: {integrity: sha512-qnGh8XJHaQ0dprrDXNQZgS0FgjI6v+V3+X8DwmaV++5Aamy6jGKfDdQ1TUvhUxtmKFAbEf4/WeO5QZX+5WSngg==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -12305,17 +12305,17 @@ snapshots: '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 - '@babel/generator@7.29.7': + '@babel/generator@7.29.8': dependencies: - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 '@babel/helper-annotate-as-pure@7.29.7': dependencies: - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@babel/helper-compilation-targets@7.28.6': dependencies: @@ -12341,7 +12341,7 @@ snapshots: '@babel/helper-optimise-call-expression': 7.29.7 '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.0) '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.8 semver: 6.3.1 transitivePeerDependencies: - supports-color @@ -12370,8 +12370,8 @@ snapshots: '@babel/helper-member-expression-to-functions@7.29.7': dependencies: - '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color @@ -12395,8 +12395,8 @@ snapshots: '@babel/helper-module-imports@7.29.7': dependencies: - '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color @@ -12423,13 +12423,13 @@ snapshots: '@babel/core': 7.29.0 '@babel/helper-module-imports': 7.29.7 '@babel/helper-validator-identifier': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.8 transitivePeerDependencies: - supports-color '@babel/helper-optimise-call-expression@7.29.7': dependencies: - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@babel/helper-plugin-utils@7.28.6': {} @@ -12440,7 +12440,7 @@ snapshots: '@babel/core': 7.29.0 '@babel/helper-annotate-as-pure': 7.29.7 '@babel/helper-wrap-function': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.8 transitivePeerDependencies: - supports-color @@ -12449,14 +12449,14 @@ snapshots: '@babel/core': 7.29.0 '@babel/helper-member-expression-to-functions': 7.29.7 '@babel/helper-optimise-call-expression': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.8 transitivePeerDependencies: - supports-color '@babel/helper-skip-transparent-expression-wrappers@7.29.7': dependencies: - '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color @@ -12475,8 +12475,8 @@ snapshots: '@babel/helper-wrap-function@7.29.7': dependencies: '@babel/template': 7.29.7 - '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color @@ -12502,15 +12502,15 @@ snapshots: dependencies: '@babel/types': 7.29.0 - '@babel/parser@7.29.7': + '@babel/parser@7.29.8': dependencies: - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.29.7(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.8 transitivePeerDependencies: - supports-color @@ -12545,7 +12545,7 @@ snapshots: dependencies: '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.8 transitivePeerDependencies: - supports-color @@ -12589,7 +12589,7 @@ snapshots: '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.29.7 '@babel/helper-remap-async-to-generator': 7.29.7(@babel/core@7.29.0) - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.8 transitivePeerDependencies: - supports-color @@ -12636,7 +12636,7 @@ snapshots: '@babel/helper-globals': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.0) - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.8 transitivePeerDependencies: - supports-color @@ -12650,7 +12650,7 @@ snapshots: dependencies: '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.8 transitivePeerDependencies: - supports-color @@ -12707,7 +12707,7 @@ snapshots: '@babel/core': 7.29.0 '@babel/helper-compilation-targets': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.8 transitivePeerDependencies: - supports-color @@ -12747,13 +12747,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-systemjs@7.29.7(@babel/core@7.29.0)': + '@babel/plugin-transform-modules-systemjs@7.29.8(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.0) '@babel/helper-plugin-utils': 7.29.7 '@babel/helper-validator-identifier': 7.29.7 - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.8 transitivePeerDependencies: - supports-color @@ -12793,7 +12793,7 @@ snapshots: '@babel/helper-plugin-utils': 7.29.7 '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.0) '@babel/plugin-transform-parameters': 7.29.7(@babel/core@7.29.0) - '@babel/traverse': 7.29.7 + '@babel/traverse': 7.29.8 transitivePeerDependencies: - supports-color @@ -12845,7 +12845,7 @@ snapshots: '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-regenerator@7.29.7(@babel/core@7.29.0)': + '@babel/plugin-transform-regenerator@7.29.8(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.29.7 @@ -12866,7 +12866,7 @@ snapshots: '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-spread@7.29.7(@babel/core@7.29.0)': + '@babel/plugin-transform-spread@7.29.8(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.29.7 @@ -12954,7 +12954,7 @@ snapshots: '@babel/plugin-transform-member-expression-literals': 7.29.7(@babel/core@7.29.0) '@babel/plugin-transform-modules-amd': 7.29.7(@babel/core@7.29.0) '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.0) - '@babel/plugin-transform-modules-systemjs': 7.29.7(@babel/core@7.29.0) + '@babel/plugin-transform-modules-systemjs': 7.29.8(@babel/core@7.29.0) '@babel/plugin-transform-modules-umd': 7.29.7(@babel/core@7.29.0) '@babel/plugin-transform-named-capturing-groups-regex': 7.29.7(@babel/core@7.29.0) '@babel/plugin-transform-new-target': 7.29.7(@babel/core@7.29.0) @@ -12968,11 +12968,11 @@ snapshots: '@babel/plugin-transform-private-methods': 7.29.7(@babel/core@7.29.0) '@babel/plugin-transform-private-property-in-object': 7.29.7(@babel/core@7.29.0) '@babel/plugin-transform-property-literals': 7.29.7(@babel/core@7.29.0) - '@babel/plugin-transform-regenerator': 7.29.7(@babel/core@7.29.0) + '@babel/plugin-transform-regenerator': 7.29.8(@babel/core@7.29.0) '@babel/plugin-transform-regexp-modifiers': 7.29.7(@babel/core@7.29.0) '@babel/plugin-transform-reserved-words': 7.29.7(@babel/core@7.29.0) '@babel/plugin-transform-shorthand-properties': 7.29.7(@babel/core@7.29.0) - '@babel/plugin-transform-spread': 7.29.7(@babel/core@7.29.0) + '@babel/plugin-transform-spread': 7.29.8(@babel/core@7.29.0) '@babel/plugin-transform-sticky-regex': 7.29.7(@babel/core@7.29.0) '@babel/plugin-transform-template-literals': 7.29.7(@babel/core@7.29.0) '@babel/plugin-transform-typeof-symbol': 7.29.7(@babel/core@7.29.0) @@ -12993,7 +12993,7 @@ snapshots: dependencies: '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 esutils: 2.0.3 '@babel/runtime@7.25.0': @@ -13021,8 +13021,8 @@ snapshots: '@babel/template@7.29.7': dependencies: '@babel/code-frame': 7.29.7 - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 '@babel/traverse@7.28.5': dependencies: @@ -13060,14 +13060,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/traverse@7.29.7': + '@babel/traverse@7.29.8': dependencies: '@babel/code-frame': 7.29.7 - '@babel/generator': 7.29.7 + '@babel/generator': 7.29.8 '@babel/helper-globals': 7.29.7 - '@babel/parser': 7.29.7 + '@babel/parser': 7.29.8 '@babel/template': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 debug: 4.4.3 transitivePeerDependencies: - supports-color @@ -13087,7 +13087,7 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 - '@babel/types@7.29.7': + '@babel/types@7.29.8': dependencies: '@babel/helper-string-parser': 7.29.7 '@babel/helper-validator-identifier': 7.29.7 @@ -14734,61 +14734,61 @@ snapshots: '@oxc-project/types@0.122.0': {} - '@oxfmt/binding-android-arm-eabi@0.60.0': + '@oxfmt/binding-android-arm-eabi@0.62.0': optional: true - '@oxfmt/binding-android-arm64@0.60.0': + '@oxfmt/binding-android-arm64@0.62.0': optional: true - '@oxfmt/binding-darwin-arm64@0.60.0': + '@oxfmt/binding-darwin-arm64@0.62.0': optional: true - '@oxfmt/binding-darwin-x64@0.60.0': + '@oxfmt/binding-darwin-x64@0.62.0': optional: true - '@oxfmt/binding-freebsd-x64@0.60.0': + '@oxfmt/binding-freebsd-x64@0.62.0': optional: true - '@oxfmt/binding-linux-arm-gnueabihf@0.60.0': + '@oxfmt/binding-linux-arm-gnueabihf@0.62.0': optional: true - '@oxfmt/binding-linux-arm-musleabihf@0.60.0': + '@oxfmt/binding-linux-arm-musleabihf@0.62.0': optional: true - '@oxfmt/binding-linux-arm64-gnu@0.60.0': + '@oxfmt/binding-linux-arm64-gnu@0.62.0': optional: true - '@oxfmt/binding-linux-arm64-musl@0.60.0': + '@oxfmt/binding-linux-arm64-musl@0.62.0': optional: true - '@oxfmt/binding-linux-ppc64-gnu@0.60.0': + '@oxfmt/binding-linux-ppc64-gnu@0.62.0': optional: true - '@oxfmt/binding-linux-riscv64-gnu@0.60.0': + '@oxfmt/binding-linux-riscv64-gnu@0.62.0': optional: true - '@oxfmt/binding-linux-riscv64-musl@0.60.0': + '@oxfmt/binding-linux-riscv64-musl@0.62.0': optional: true - '@oxfmt/binding-linux-s390x-gnu@0.60.0': + '@oxfmt/binding-linux-s390x-gnu@0.62.0': optional: true - '@oxfmt/binding-linux-x64-gnu@0.60.0': + '@oxfmt/binding-linux-x64-gnu@0.62.0': optional: true - '@oxfmt/binding-linux-x64-musl@0.60.0': + '@oxfmt/binding-linux-x64-musl@0.62.0': optional: true - '@oxfmt/binding-openharmony-arm64@0.60.0': + '@oxfmt/binding-openharmony-arm64@0.62.0': optional: true - '@oxfmt/binding-win32-arm64-msvc@0.60.0': + '@oxfmt/binding-win32-arm64-msvc@0.62.0': optional: true - '@oxfmt/binding-win32-ia32-msvc@0.60.0': + '@oxfmt/binding-win32-ia32-msvc@0.62.0': optional: true - '@oxfmt/binding-win32-x64-msvc@0.60.0': + '@oxfmt/binding-win32-x64-msvc@0.62.0': optional: true '@oxlint-tsgolint/darwin-arm64@7.0.2001': @@ -14809,61 +14809,61 @@ snapshots: '@oxlint-tsgolint/win32-x64@7.0.2001': optional: true - '@oxlint/binding-android-arm-eabi@1.75.0': + '@oxlint/binding-android-arm-eabi@1.77.0': optional: true - '@oxlint/binding-android-arm64@1.75.0': + '@oxlint/binding-android-arm64@1.77.0': optional: true - '@oxlint/binding-darwin-arm64@1.75.0': + '@oxlint/binding-darwin-arm64@1.77.0': optional: true - '@oxlint/binding-darwin-x64@1.75.0': + '@oxlint/binding-darwin-x64@1.77.0': optional: true - '@oxlint/binding-freebsd-x64@1.75.0': + '@oxlint/binding-freebsd-x64@1.77.0': optional: true - '@oxlint/binding-linux-arm-gnueabihf@1.75.0': + '@oxlint/binding-linux-arm-gnueabihf@1.77.0': optional: true - '@oxlint/binding-linux-arm-musleabihf@1.75.0': + '@oxlint/binding-linux-arm-musleabihf@1.77.0': optional: true - '@oxlint/binding-linux-arm64-gnu@1.75.0': + '@oxlint/binding-linux-arm64-gnu@1.77.0': optional: true - '@oxlint/binding-linux-arm64-musl@1.75.0': + '@oxlint/binding-linux-arm64-musl@1.77.0': optional: true - '@oxlint/binding-linux-ppc64-gnu@1.75.0': + '@oxlint/binding-linux-ppc64-gnu@1.77.0': optional: true - '@oxlint/binding-linux-riscv64-gnu@1.75.0': + '@oxlint/binding-linux-riscv64-gnu@1.77.0': optional: true - '@oxlint/binding-linux-riscv64-musl@1.75.0': + '@oxlint/binding-linux-riscv64-musl@1.77.0': optional: true - '@oxlint/binding-linux-s390x-gnu@1.75.0': + '@oxlint/binding-linux-s390x-gnu@1.77.0': optional: true - '@oxlint/binding-linux-x64-gnu@1.75.0': + '@oxlint/binding-linux-x64-gnu@1.77.0': optional: true - '@oxlint/binding-linux-x64-musl@1.75.0': + '@oxlint/binding-linux-x64-musl@1.77.0': optional: true - '@oxlint/binding-openharmony-arm64@1.75.0': + '@oxlint/binding-openharmony-arm64@1.77.0': optional: true - '@oxlint/binding-win32-arm64-msvc@1.75.0': + '@oxlint/binding-win32-arm64-msvc@1.77.0': optional: true - '@oxlint/binding-win32-ia32-msvc@1.75.0': + '@oxlint/binding-win32-ia32-msvc@1.77.0': optional: true - '@oxlint/binding-win32-x64-msvc@1.75.0': + '@oxlint/binding-win32-x64-msvc@1.77.0': optional: true '@oxlint/plugins@1.43.0': {} @@ -14978,7 +14978,7 @@ snapshots: '@redocly/ajv@8.18.0': dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.1.4 + fast-uri: 3.1.5 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 @@ -16920,7 +16920,7 @@ snapshots: acorn@8.15.0: {} - acorn@8.17.0: {} + acorn@8.18.0: {} add-stream@1.0.0: {} @@ -16968,7 +16968,7 @@ snapshots: ajv@8.20.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.1.4 + fast-uri: 3.1.5 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 @@ -17241,7 +17241,7 @@ snapshots: base64-js@1.5.1: {} - baseline-browser-mapping@2.11.0: {} + baseline-browser-mapping@2.11.12: {} baseline-browser-mapping@2.9.11: {} @@ -17364,7 +17364,7 @@ snapshots: dependencies: balanced-match: 1.0.2 - brace-expansion@2.1.2: + brace-expansion@2.1.4: dependencies: balanced-match: 1.0.2 @@ -17398,9 +17398,9 @@ snapshots: browserslist@4.28.5: dependencies: - baseline-browser-mapping: 2.11.0 + baseline-browser-mapping: 2.11.12 caniuse-lite: 1.0.30001806 - electron-to-chromium: 1.5.395 + electron-to-chromium: 1.5.399 node-releases: 2.0.51 update-browserslist-db: 1.2.3(browserslist@4.28.5) @@ -18389,7 +18389,7 @@ snapshots: electron-to-chromium@1.5.267: {} - electron-to-chromium@1.5.395: {} + electron-to-chromium@1.5.399: {} emoji-regex@8.0.0: {} @@ -18955,7 +18955,7 @@ snapshots: fast-safe-stringify@2.1.1: {} - fast-uri@3.1.4: {} + fast-uri@3.1.5: {} fast-url-parser@1.1.3: dependencies: @@ -20958,7 +20958,7 @@ snapshots: minimatch@5.1.9: dependencies: - brace-expansion: 2.1.2 + brace-expansion: 2.1.4 minimatch@6.2.3: dependencies: @@ -21422,7 +21422,7 @@ snapshots: nanoid@3.3.12: {} - nanoid@3.3.16: {} + nanoid@3.3.17: {} natural-compare@1.4.0: {} @@ -21723,29 +21723,29 @@ snapshots: object-keys: 1.1.1 safe-push-apply: 1.0.0 - oxfmt@0.60.0: + oxfmt@0.62.0: dependencies: tinypool: 2.1.0 optionalDependencies: - '@oxfmt/binding-android-arm-eabi': 0.60.0 - '@oxfmt/binding-android-arm64': 0.60.0 - '@oxfmt/binding-darwin-arm64': 0.60.0 - '@oxfmt/binding-darwin-x64': 0.60.0 - '@oxfmt/binding-freebsd-x64': 0.60.0 - '@oxfmt/binding-linux-arm-gnueabihf': 0.60.0 - '@oxfmt/binding-linux-arm-musleabihf': 0.60.0 - '@oxfmt/binding-linux-arm64-gnu': 0.60.0 - '@oxfmt/binding-linux-arm64-musl': 0.60.0 - '@oxfmt/binding-linux-ppc64-gnu': 0.60.0 - '@oxfmt/binding-linux-riscv64-gnu': 0.60.0 - '@oxfmt/binding-linux-riscv64-musl': 0.60.0 - '@oxfmt/binding-linux-s390x-gnu': 0.60.0 - '@oxfmt/binding-linux-x64-gnu': 0.60.0 - '@oxfmt/binding-linux-x64-musl': 0.60.0 - '@oxfmt/binding-openharmony-arm64': 0.60.0 - '@oxfmt/binding-win32-arm64-msvc': 0.60.0 - '@oxfmt/binding-win32-ia32-msvc': 0.60.0 - '@oxfmt/binding-win32-x64-msvc': 0.60.0 + '@oxfmt/binding-android-arm-eabi': 0.62.0 + '@oxfmt/binding-android-arm64': 0.62.0 + '@oxfmt/binding-darwin-arm64': 0.62.0 + '@oxfmt/binding-darwin-x64': 0.62.0 + '@oxfmt/binding-freebsd-x64': 0.62.0 + '@oxfmt/binding-linux-arm-gnueabihf': 0.62.0 + '@oxfmt/binding-linux-arm-musleabihf': 0.62.0 + '@oxfmt/binding-linux-arm64-gnu': 0.62.0 + '@oxfmt/binding-linux-arm64-musl': 0.62.0 + '@oxfmt/binding-linux-ppc64-gnu': 0.62.0 + '@oxfmt/binding-linux-riscv64-gnu': 0.62.0 + '@oxfmt/binding-linux-riscv64-musl': 0.62.0 + '@oxfmt/binding-linux-s390x-gnu': 0.62.0 + '@oxfmt/binding-linux-x64-gnu': 0.62.0 + '@oxfmt/binding-linux-x64-musl': 0.62.0 + '@oxfmt/binding-openharmony-arm64': 0.62.0 + '@oxfmt/binding-win32-arm64-msvc': 0.62.0 + '@oxfmt/binding-win32-ia32-msvc': 0.62.0 + '@oxfmt/binding-win32-x64-msvc': 0.62.0 oxlint-tsgolint@7.0.2001: optionalDependencies: @@ -21756,27 +21756,27 @@ snapshots: '@oxlint-tsgolint/win32-arm64': 7.0.2001 '@oxlint-tsgolint/win32-x64': 7.0.2001 - oxlint@1.75.0(oxlint-tsgolint@7.0.2001): + oxlint@1.77.0(oxlint-tsgolint@7.0.2001): optionalDependencies: - '@oxlint/binding-android-arm-eabi': 1.75.0 - '@oxlint/binding-android-arm64': 1.75.0 - '@oxlint/binding-darwin-arm64': 1.75.0 - '@oxlint/binding-darwin-x64': 1.75.0 - '@oxlint/binding-freebsd-x64': 1.75.0 - '@oxlint/binding-linux-arm-gnueabihf': 1.75.0 - '@oxlint/binding-linux-arm-musleabihf': 1.75.0 - '@oxlint/binding-linux-arm64-gnu': 1.75.0 - '@oxlint/binding-linux-arm64-musl': 1.75.0 - '@oxlint/binding-linux-ppc64-gnu': 1.75.0 - '@oxlint/binding-linux-riscv64-gnu': 1.75.0 - '@oxlint/binding-linux-riscv64-musl': 1.75.0 - '@oxlint/binding-linux-s390x-gnu': 1.75.0 - '@oxlint/binding-linux-x64-gnu': 1.75.0 - '@oxlint/binding-linux-x64-musl': 1.75.0 - '@oxlint/binding-openharmony-arm64': 1.75.0 - '@oxlint/binding-win32-arm64-msvc': 1.75.0 - '@oxlint/binding-win32-ia32-msvc': 1.75.0 - '@oxlint/binding-win32-x64-msvc': 1.75.0 + '@oxlint/binding-android-arm-eabi': 1.77.0 + '@oxlint/binding-android-arm64': 1.77.0 + '@oxlint/binding-darwin-arm64': 1.77.0 + '@oxlint/binding-darwin-x64': 1.77.0 + '@oxlint/binding-freebsd-x64': 1.77.0 + '@oxlint/binding-linux-arm-gnueabihf': 1.77.0 + '@oxlint/binding-linux-arm-musleabihf': 1.77.0 + '@oxlint/binding-linux-arm64-gnu': 1.77.0 + '@oxlint/binding-linux-arm64-musl': 1.77.0 + '@oxlint/binding-linux-ppc64-gnu': 1.77.0 + '@oxlint/binding-linux-riscv64-gnu': 1.77.0 + '@oxlint/binding-linux-riscv64-musl': 1.77.0 + '@oxlint/binding-linux-s390x-gnu': 1.77.0 + '@oxlint/binding-linux-x64-gnu': 1.77.0 + '@oxlint/binding-linux-x64-musl': 1.77.0 + '@oxlint/binding-openharmony-arm64': 1.77.0 + '@oxlint/binding-win32-arm64-msvc': 1.77.0 + '@oxlint/binding-win32-ia32-msvc': 1.77.0 + '@oxlint/binding-win32-x64-msvc': 1.77.0 oxlint-tsgolint: 7.0.2001 p-defer@3.0.0: {} @@ -22053,7 +22053,7 @@ snapshots: postcss@8.5.15: dependencies: - nanoid: 3.3.16 + nanoid: 3.3.17 picocolors: 1.1.1 source-map-js: 1.2.1 @@ -23694,7 +23694,7 @@ snapshots: terser@5.49.0: dependencies: '@jridgewell/source-map': 0.3.11 - acorn: 8.17.0 + acorn: 8.18.0 commander: 2.20.3 source-map-support: 0.5.21