refactor(schema): simplify validation and OpenAPI generation (#2709)

This commit is contained in:
Hampus authored and GitHub committed 2026-09-11 23:24:26 +02:00
1 parent 4bc5593f9f
commit de1fd95a99
510 files changed
+29494 -36131

No files matched your search

@@ -25,7 +25,7 @@ export const AutocompleteChannel = observer(
options: Array<AutocompleteOption>;
onMouseEnter: (index: number) => void;
onMouseLeave: () => void;
rowRefs?: React.MutableRefObject<Array<HTMLButtonElement | null>>;
rowRefs?: React.RefObject<Array<HTMLButtonElement | null>>;
getOptionId?: (index: number) => string;
}) => {
const channels = options.filter(isChannel);
@@ -3,7 +3,7 @@
import {type AutocompleteOption, isCommand} from '@app/features/channel/components/Autocomplete';
import {AutocompleteItem} from '@app/features/channel/components/AutocompleteItem';
import {observer} from 'mobx-react-lite';
import type {MutableRefObject} from 'react';
import type {RefObject} from 'react';
interface Props {
onSelect: (option: AutocompleteOption) => void;
@@ -12,7 +12,7 @@ interface Props {
options: Array<AutocompleteOption>;
onMouseEnter: (index: number) => void;
onMouseLeave: () => void;
rowRefs?: MutableRefObject<Array<HTMLButtonElement | null>>;
rowRefs?: RefObject<Array<HTMLButtonElement | null>>;
getOptionId?: (index: number) => string;
}
@@ -11,7 +11,7 @@ interface AutocompleteCommandChoiceProps {
options: Array<AutocompleteOption>;
onMouseEnter: (index: number) => void;
onMouseLeave: () => void;
rowRefs?: React.MutableRefObject<Array<HTMLButtonElement | null>>;
rowRefs?: React.RefObject<Array<HTMLButtonElement | null>>;
getOptionId?: (index: number) => string;
}
@@ -11,7 +11,7 @@ interface AutocompleteCommandOptionalAddProps {
options: Array<AutocompleteOption>;
onMouseEnter: (index: number) => void;
onMouseLeave: () => void;
rowRefs?: React.MutableRefObject<Array<HTMLButtonElement | null>>;
rowRefs?: React.RefObject<Array<HTMLButtonElement | null>>;
getOptionId?: (index: number) => string;
}
@@ -97,7 +97,7 @@ export const AutocompleteEmoji = observer(
options: Array<AutocompleteOption>;
onMouseEnter: (index: number) => void;
onMouseLeave: () => void;
rowRefs?: React.MutableRefObject<Array<HTMLButtonElement | null>>;
rowRefs?: React.RefObject<Array<HTMLButtonElement | null>>;
getOptionId?: (index: number) => string;
}) => {
const {i18n} = useLingui();
@@ -85,7 +85,7 @@ export const AutocompleteGif = observer(
options: Array<AutocompleteOption>;
onMouseEnter: (index: number) => void;
onMouseLeave: () => void;
rowRefs?: React.MutableRefObject<Array<HTMLButtonElement | null>>;
rowRefs?: React.RefObject<Array<HTMLButtonElement | null>>;
getOptionId?: (index: number) => string;
}) => {
const {i18n} = useLingui();
@@ -24,7 +24,7 @@ export const AutocompleteMeme = observer(
options: Array<AutocompleteOption>;
onMouseEnter: (index: number) => void;
onMouseLeave: () => void;
rowRefs?: React.MutableRefObject<Array<HTMLButtonElement | null>>;
rowRefs?: React.RefObject<Array<HTMLButtonElement | null>>;
getOptionId?: (index: number) => string;
}) => {
const memes = options.filter(isMeme);
@@ -37,7 +37,7 @@ const NOTIFY_USERS_WITH_THIS_ROLE_WHO_HAVE_PERMISSION_DESCRIPTOR = msg({
comment: 'Description text in the channel and chat autocomplete mention. Keep the tone plain and specific.',
});
type RowRef = React.MutableRefObject<Array<HTMLButtonElement | null>> | undefined;
type RowRef = React.RefObject<Array<HTMLButtonElement | null>> | undefined;
type OptionIdGetter = ((index: number) => string) | undefined;
function resolveOptionId(getOptionId: OptionIdGetter, index: number): string | undefined {
@@ -76,7 +76,7 @@ export const AutocompleteMention = observer(function AutocompleteMention({
options: Array<AutocompleteOption>;
onMouseEnter: (index: number) => void;
onMouseLeave: () => void;
rowRefs?: React.MutableRefObject<Array<HTMLButtonElement | null>>;
rowRefs?: React.RefObject<Array<HTMLButtonElement | null>>;
getOptionId?: (index: number) => string;
}) {
const {i18n} = useLingui();
@@ -43,7 +43,7 @@ export const AutocompleteSticker = observer(
options: Array<AutocompleteOption>;
onMouseEnter: (index: number) => void;
onMouseLeave: () => void;
rowRefs?: React.MutableRefObject<Array<HTMLButtonElement | null>>;
rowRefs?: React.RefObject<Array<HTMLButtonElement | null>>;
getOptionId?: (index: number) => string;
}) => {
const stickers = options.filter(isSticker);
@@ -2,7 +2,7 @@
import type {Channel} from '@app/features/channel/models/Channel';
import type {Message} from '@app/features/messaging/models/MessagingMessage';
import {assign, getInitialSnapshot, type SnapshotFrom, setup, transition} from 'xstate';
import {assign, initialTransition, type SnapshotFrom, setup, transition} from 'xstate';
export interface SearchMachineStateIdle {
status: 'idle';
@@ -132,7 +132,7 @@ export const searchStateMachine = setup({
export type SearchMachineSnapshot = SnapshotFrom<typeof searchStateMachine>;
export function createSearchMachineSnapshot(): SearchMachineSnapshot {
return getInitialSnapshot(searchStateMachine);
return initialTransition(searchStateMachine)[0];
}
export function transitionSearchMachineSnapshot(
@@ -123,7 +123,7 @@ export const AddFriendForm: React.FC<AddFriendFormProps> = observer(({onSuccess}
}
return getSendFriendRequestErrorMessage(i18n, errorCode, null);
};
const handleSubmit = (e: React.FormEvent) => {
const handleSubmit = (e: React.SubmitEvent<HTMLFormElement>) => {
e.preventDefault();
const [username, discriminator] = parseInput(input['trim']());
if (!username || !discriminator || !/^\d{4}$/.test(discriminator)) {
@@ -34,7 +34,7 @@ interface VirtualRowRendererProps {
selectedColumnInRow: number;
emojiRowIndex: number;
shouldScrollOnSelection?: boolean;
emojiRefs: React.MutableRefObject<Map<string, HTMLButtonElement>>;
emojiRefs: React.RefObject<Map<string, HTMLButtonElement>>;
}
const VirtualRowRenderer: React.FC<VirtualRowRendererProps> = React.memo(
@@ -208,7 +208,7 @@ interface VirtualizedRowProps {
selectedColumn: number;
emojiRowIndex: number;
shouldScrollOnSelection?: boolean;
emojiRefs: React.MutableRefObject<Map<string, HTMLButtonElement>>;
emojiRefs: React.RefObject<Map<string, HTMLButtonElement>>;
}
export const VirtualizedRow: React.FC<VirtualizedRowProps> = observer(
@@ -33,7 +33,7 @@ export interface MembersPaginationProps {
isSearching: boolean;
activeEllipsis: PaginationEllipsisSide | null;
pageJumpValue: string;
ellipsisInputRef: React.MutableRefObject<HTMLInputElement | null>;
ellipsisInputRef: React.RefObject<HTMLInputElement | null>;
onPageSelect: (page: number) => void;
setActiveEllipsis: React.Dispatch<React.SetStateAction<PaginationEllipsisSide | null>>;
setPageJumpValue: React.Dispatch<React.SetStateAction<string>>;
@@ -57,7 +57,7 @@ export function MembersPagination({
setPageJumpValue('');
}, [setActiveEllipsis, setPageJumpValue]);
const handleJumpSubmit = useCallback(
(event: React.FormEvent<HTMLFormElement>) => {
(event: React.SubmitEvent<HTMLFormElement>) => {
event.preventDefault();
const nextPage = parseInt(pageJumpValue, 10);
if (!Number.isNaN(nextPage) && nextPage >= 1 && nextPage <= totalPages) {
@@ -21,7 +21,7 @@ export interface MembersTableFooterProps {
isSearching: boolean;
activeEllipsis: PaginationEllipsisSide | null;
pageJumpValue: string;
ellipsisInputRef: React.MutableRefObject<HTMLInputElement | null>;
ellipsisInputRef: React.RefObject<HTMLInputElement | null>;
onPageSelect: (page: number) => void;
setActiveEllipsis: React.Dispatch<React.SetStateAction<PaginationEllipsisSide | null>>;
setPageJumpValue: React.Dispatch<React.SetStateAction<string>>;
@@ -254,7 +254,7 @@ export function assignRef<T>(ref: React.Ref<T> | undefined, value: T | null): vo
ref(value);
return;
}
(ref as React.MutableRefObject<T | null>).current = value;
ref.current = value;
}
export function normalizeFilterKey(filterKey: string): string {
@@ -90,10 +90,7 @@ const UNNAMED_DESCRIPTOR = msg({
comment: 'Short label in the channel and chat use message search autocomplete. Keep it concise.',
});
function resolveInputCursorPosition(
inputRef: React.MutableRefObject<LexicalSearchInputHandle | null>,
value: string,
): number {
function resolveInputCursorPosition(inputRef: React.RefObject<LexicalSearchInputHandle | null>, value: string): number {
const input = inputRef.current;
if (input == null) {
return value.length;
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import type {View} from '@app/features/channel/components/pickers/gif/GifPickerTypes';
import {assign, getInitialSnapshot, type SnapshotFrom, setup, transition} from 'xstate';
import {assign, initialTransition, type SnapshotFrom, setup, transition} from 'xstate';
declare const gifPickerRequestIdBrand: unique symbol;
@@ -576,7 +576,7 @@ export const gifPickerStateMachine = setup({
});
export function createGifPickerSnapshot(): GifPickerMachineSnapshot {
return getInitialSnapshot(gifPickerStateMachine);
return initialTransition(gifPickerStateMachine)[0];
}
export function transitionGifPickerSnapshot(
@@ -59,7 +59,7 @@ const assignRef = <T,>(ref: React.Ref<T> | null | undefined, value: T | null) =>
ref(value);
return;
}
(ref as React.MutableRefObject<T | null>).current = value;
ref.current = value;
};
export const PickerSearchInput = React.forwardRef<HTMLInputElement, PickerSearchInputProps>(
(
@@ -32,7 +32,7 @@ interface VirtualRowRendererProps {
selectedColumn: number;
stickerRowIndex: number;
shouldScrollOnSelection?: boolean;
stickerRefs: React.MutableRefObject<Map<string, HTMLButtonElement>>;
stickerRefs: React.RefObject<Map<string, HTMLButtonElement>>;
channel?: Channel | null;
}
@@ -40,7 +40,7 @@ interface StickerButtonProps {
sticker: GuildSticker;
stickerKey: string;
isSelected: boolean;
stickerRefs: React.MutableRefObject<Map<string, HTMLButtonElement>>;
stickerRefs: React.RefObject<Map<string, HTMLButtonElement>>;
shouldScrollOnSelection?: boolean;
handleStickerClick: (event: React.MouseEvent<HTMLButtonElement>) => void;
handleContextMenu: (event: React.MouseEvent<HTMLButtonElement>) => void;
@@ -296,7 +296,7 @@ interface VirtualRowWrapperProps {
selectedColumn: number;
stickerRowIndex: number;
shouldScrollOnSelection?: boolean;
stickerRefs: React.MutableRefObject<Map<string, HTMLButtonElement>>;
stickerRefs: React.RefObject<Map<string, HTMLButtonElement>>;
channel?: Channel | null;
}
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {hasVisibleMessageContent} from '@app/features/messaging/utils/VisibleMessageContent';
import {assign, getInitialSnapshot, type SnapshotFrom, setup, transition} from 'xstate';
import {assign, initialTransition, type SnapshotFrom, setup, transition} from 'xstate';
export type MobileTextareaVisibleButton = 'send' | 'voice';
export type MobileTextareaButtonMode = 'voice' | 'sendReady' | 'sendBlocked';
@@ -144,7 +144,7 @@ export const mobileTextareaButtonStateMachine = setup({
export type MobileTextareaButtonSnapshot = SnapshotFrom<typeof mobileTextareaButtonStateMachine>;
export function createMobileTextareaButtonSnapshot(): MobileTextareaButtonSnapshot {
return getInitialSnapshot(mobileTextareaButtonStateMachine);
return initialTransition(mobileTextareaButtonStateMachine)[0];
}
export function transitionMobileTextareaButtonSnapshot(
@@ -36,7 +36,7 @@ interface TextareaInputFieldProps {
placeholder: string;
textareaRef: React.RefObject<HTMLTextAreaElement | null>;
scrollerRef?: React.RefObject<ScrollerHandle | null>;
shouldStickToBottomRef?: React.MutableRefObject<boolean>;
shouldStickToBottomRef?: React.RefObject<boolean>;
isFocused?: boolean;
isAutocompleteAttached: boolean;
autocompleteListId?: string;