mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-19 05:55:34 +09:00
refactor(schema): simplify validation and OpenAPI generation (#2709)
This commit is contained in:
1 parent
4bc5593f9f
commit
de1fd95a99
510 files changed
+29494
-36131
No files matched your search
@@ -1,12 +1,17 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import assert from 'node:assert/strict';
|
||||
import {registerComposerEnter} from '@app/features/lexical/composer/ComposerEnter';
|
||||
import {$replaceComposerRange, $selectComposerRange} from '@app/features/lexical/composer/composerOffsets';
|
||||
import {ComposerMentionNode} from '@app/features/lexical/composer/nodes/ComposerMentionNode';
|
||||
import {ComposerPlainSegmentNode} from '@app/features/lexical/composer/nodes/ComposerPlainSegmentNode';
|
||||
import {$createSlashSlotNode, SlashSlotNode} from '@app/features/lexical/composer/nodes/SlashSlotNode';
|
||||
import {
|
||||
$createSlashSlotNode,
|
||||
$isSlashSlotNode,
|
||||
SlashSlotNode,
|
||||
} from '@app/features/lexical/composer/nodes/SlashSlotNode';
|
||||
import {SlashSlotPlaceholderNode} from '@app/features/lexical/composer/nodes/SlashSlotPlaceholderNode';
|
||||
import {$getRoot, $setSelection, createEditor, type ElementNode, KEY_ENTER_COMMAND, type LexicalEditor} from 'lexical';
|
||||
import {$getRoot, $isElementNode, $setSelection, createEditor, KEY_ENTER_COMMAND, type LexicalEditor} from 'lexical';
|
||||
import {describe, expect, it, vi} from 'vitest';
|
||||
|
||||
vi.mock('@app/features/lexical/composer/nodes/ComposerMentionPill', () => ({ComposerMentionPill: () => null}));
|
||||
@@ -45,16 +50,22 @@ function typedWithRequiredSlot(text: string, offset: number): LexicalEditor {
|
||||
return createComposer(() => {
|
||||
$replaceComposerRange(0, 0, {kind: 'text', text}, {leading: false, trailing: false});
|
||||
const slot = $createSlashSlotNode('value', 'string', true);
|
||||
$getRoot().getFirstChildOrThrow<ElementNode>().append(slot);
|
||||
const paragraph = $getRoot().getFirstChildOrThrow();
|
||||
assert($isElementNode(paragraph), 'Expected composer paragraph');
|
||||
paragraph.append(slot);
|
||||
slot.ensurePlaceholder();
|
||||
$selectComposerRange(offset, offset);
|
||||
});
|
||||
}
|
||||
|
||||
function slotValidity(editor: LexicalEditor): string {
|
||||
return editor.read(() =>
|
||||
$getRoot().getFirstChildOrThrow<ElementNode>().getLastChildOrThrow<SlashSlotNode>().getValidity(),
|
||||
);
|
||||
return editor.read(() => {
|
||||
const paragraph = $getRoot().getFirstChildOrThrow();
|
||||
assert($isElementNode(paragraph), 'Expected composer paragraph');
|
||||
const slot = paragraph.getLastChildOrThrow();
|
||||
assert($isSlashSlotNode(slot), 'Expected required slash command slot');
|
||||
return slot.getValidity();
|
||||
});
|
||||
}
|
||||
|
||||
function pressEnter(
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import assert from 'node:assert/strict';
|
||||
import {registerComposerMarkdownHighlight} from '@app/features/lexical/composer/ComposerMarkdownHighlight';
|
||||
import {$hydrateComposerFromDraft, $projectComposer} from '@app/features/lexical/composer/ComposerSerialization';
|
||||
import {$getComposerSelectionRange, $selectComposerRange} from '@app/features/lexical/composer/composerOffsets';
|
||||
@@ -24,7 +25,6 @@ import {
|
||||
$isElementNode,
|
||||
$isTextNode,
|
||||
createEditor,
|
||||
type ElementNode,
|
||||
type LexicalEditor,
|
||||
type RangeSelection,
|
||||
} from 'lexical';
|
||||
@@ -282,7 +282,9 @@ describe('registerComposerMarkdownHighlight with silentMessagePrefix', () => {
|
||||
]);
|
||||
expect(readLines(editor)).toEqual([[['@silent', SILENT_STYLE], [' ', ''], 'composer-mention']]);
|
||||
const mention = editor.getEditorState().read(() => {
|
||||
const pill = $getRoot().getFirstChildOrThrow<ElementNode>().getLastChild();
|
||||
const paragraph = $getRoot().getFirstChildOrThrow();
|
||||
assert($isElementNode(paragraph), 'Expected composer paragraph');
|
||||
const pill = paragraph.getLastChild();
|
||||
return $isComposerMentionNode(pill) ? {literal: pill.isLiteral(), presentation: pill.getPresentation()} : null;
|
||||
});
|
||||
expect(mention).toEqual({literal: false, presentation: ComposerMentionPresentation.none});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import assert from 'node:assert/strict';
|
||||
import {
|
||||
$getComposerClipboardSelection,
|
||||
$insertComposerClipboardSlice,
|
||||
@@ -42,6 +43,7 @@ import {
|
||||
$createTextNode,
|
||||
$getRoot,
|
||||
$getSelection,
|
||||
$isElementNode,
|
||||
$isRangeSelection,
|
||||
$setCompositionKey,
|
||||
$setSelection,
|
||||
@@ -142,7 +144,9 @@ function describeNode(node: LexicalNode): string {
|
||||
}
|
||||
|
||||
function $paragraph(): ElementNode {
|
||||
return $getRoot().getFirstChildOrThrow<ElementNode>();
|
||||
const paragraph = $getRoot().getFirstChildOrThrow();
|
||||
assert($isElementNode(paragraph), 'Expected composer paragraph');
|
||||
return paragraph;
|
||||
}
|
||||
|
||||
function children(editor: LexicalEditor): Array<string> {
|
||||
@@ -517,9 +521,13 @@ describe('typed special mentions', () => {
|
||||
'text:@everyone ',
|
||||
'slash-slot:@here ',
|
||||
]);
|
||||
expect(editor.read(() => $paragraph().getLastChildOrThrow<ElementNode>().getChildren().map(describeNode))).toEqual([
|
||||
'text:@here ',
|
||||
]);
|
||||
expect(
|
||||
editor.read(() => {
|
||||
const slot = $paragraph().getLastChildOrThrow();
|
||||
assert($isElementNode(slot), 'Expected slash command slot element');
|
||||
return slot.getChildren().map(describeNode);
|
||||
}),
|
||||
).toEqual(['text:@here ']);
|
||||
});
|
||||
|
||||
it('restores a draft special mention and projects it back unchanged', () => {
|
||||
|
||||
@@ -37,7 +37,7 @@ export interface ComposerTypeaheadPluginProps {
|
||||
listboxId: string;
|
||||
enabled: boolean;
|
||||
onSelect: (option: AutocompleteOption) => void;
|
||||
activeRef: React.MutableRefObject<boolean>;
|
||||
activeRef: React.RefObject<boolean>;
|
||||
}
|
||||
|
||||
export const ComposerTypeaheadPlugin = ({
|
||||
|
||||
@@ -250,7 +250,7 @@ function SelectionToolbarSurface({
|
||||
onFocusRequestHandled: () => void;
|
||||
onDismiss: () => void;
|
||||
toolbarRef: React.RefObject<HTMLElement | null>;
|
||||
savedSelectionRef: React.MutableRefObject<ComposerSelectionOffsets | null>;
|
||||
savedSelectionRef: React.RefObject<ComposerSelectionOffsets | null>;
|
||||
}) {
|
||||
const {i18n} = useLingui();
|
||||
const [focusIndex, setFocusIndex] = useState(0);
|
||||
|
||||
@@ -33,7 +33,7 @@ export interface SlashSlotAutocompletePluginProps {
|
||||
listboxId: string;
|
||||
enabled: boolean;
|
||||
onSelect: (option: AutocompleteOption) => void;
|
||||
activeRef: React.MutableRefObject<boolean>;
|
||||
activeRef: React.RefObject<boolean>;
|
||||
}
|
||||
|
||||
export const SlashSlotAutocompletePlugin = ({
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import assert from 'node:assert/strict';
|
||||
import {registerComposerMarkdownHighlight} from '@app/features/lexical/composer/ComposerMarkdownHighlight';
|
||||
import {type CodeBlockWrapPlan, planCodeBlockWrap} from '@app/features/lexical/composer/codeBlockWrap';
|
||||
import {
|
||||
@@ -25,8 +26,8 @@ import {createEmptyHistoryState, registerHistory} from '@lexical/history';
|
||||
import {
|
||||
$getNodeByKey,
|
||||
$getRoot,
|
||||
$isElementNode,
|
||||
createEditor,
|
||||
type ElementNode,
|
||||
type LexicalEditor,
|
||||
type NodeKey,
|
||||
REDO_COMMAND,
|
||||
@@ -307,13 +308,14 @@ function composerState(editor: LexicalEditor): {
|
||||
}
|
||||
|
||||
function atomicKeys(editor: LexicalEditor): Array<NodeKey> {
|
||||
return editor.read(() =>
|
||||
$getRoot()
|
||||
.getFirstChildOrThrow<ElementNode>()
|
||||
return editor.read(() => {
|
||||
const paragraph = $getRoot().getFirstChildOrThrow();
|
||||
assert($isElementNode(paragraph), 'Expected composer paragraph');
|
||||
return paragraph
|
||||
.getChildren()
|
||||
.filter((node) => $isComposerMentionNode(node) || $isComposerCustomEmojiNode(node))
|
||||
.map((node) => node.getKey()),
|
||||
);
|
||||
.map((node) => node.getKey());
|
||||
});
|
||||
}
|
||||
|
||||
function atomicState(editor: LexicalEditor, keys: Array<NodeKey>): Array<{attached: boolean; literal: boolean} | null> {
|
||||
|
||||
Reference in new issue
Block a user