mirror of
https://github.com/outline/outline.git
synced 2026-05-25 05:09:20 -05:00
chore: promote no-explicit-any from warn to error (#12244)
* chore: promote no-explicit-any from warn to error and resolve violations Upgrades the oxlint rule severity and removes all 40 existing `no-explicit-any` warnings across the codebase. Most call sites gained proper types (SharedEditor refs, JSONNode/JSONMark for ProseMirror JSON walking, DocumentsStore, dd-trace `Span` parameter inference, prosemirror Fragment public API in place of internal `(fragment as any).content`). A few load-bearing `any` uses were preserved with scoped disable comments where changing the type would cascade widely (Sequelize JSONB columns on `Event`, the `withTracing` higher-order function generic, `Extension.options` consumed by many subclasses, dd-trace's `req` patching). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -31,7 +31,7 @@
|
||||
"no-empty-pattern": "error",
|
||||
"no-empty-static-block": "error",
|
||||
"no-ex-assign": "error",
|
||||
"no-explicit-any": "warn",
|
||||
"no-explicit-any": "error",
|
||||
"no-extra-boolean-cast": "error",
|
||||
"no-fallthrough": "error",
|
||||
"no-func-assign": "error",
|
||||
|
||||
@@ -119,10 +119,12 @@ export default class ComponentView {
|
||||
// Apply classes from inline decorations.
|
||||
this.decorations.forEach((decoration) => {
|
||||
// For inline decorations, attrs contain the class property.
|
||||
const attrs = (decoration as any).type?.attrs;
|
||||
const attrs = (
|
||||
decoration as Decoration & { type?: { attrs?: { class?: string } } }
|
||||
).type?.attrs;
|
||||
if (attrs?.class) {
|
||||
const classes = attrs.class.split(" ");
|
||||
classes.forEach((className: string) => {
|
||||
classes.forEach((className) => {
|
||||
if (className && this.dom) {
|
||||
this.dom.classList.add(className);
|
||||
}
|
||||
|
||||
@@ -345,7 +345,7 @@ function SuggestionsMenu<T extends MenuItem>(props: Props<T>) {
|
||||
}
|
||||
};
|
||||
|
||||
const triggerFilePick = (accept: string, attrs?: Record<string, any>) => {
|
||||
const triggerFilePick = (accept: string, attrs?: Record<string, unknown>) => {
|
||||
if (inputRef.current) {
|
||||
if (accept) {
|
||||
inputRef.current.accept = accept;
|
||||
@@ -887,7 +887,7 @@ function SuggestionsMenu<T extends MenuItem>(props: Props<T>) {
|
||||
onPointerMove={handlePointerMove}
|
||||
onPointerDown={handlePointerDown}
|
||||
>
|
||||
{props.renderMenuItem(item as any, index, {
|
||||
{props.renderMenuItem(item as unknown as T, index, {
|
||||
selected: index === selectedIndex,
|
||||
disclosure: hasChildren,
|
||||
onClick: handleOnClick,
|
||||
@@ -1053,7 +1053,7 @@ function SuggestionsMenu<T extends MenuItem>(props: Props<T>) {
|
||||
key={`sub-${childIndex}-${child.name}`}
|
||||
onPointerMove={handleChildPointerMove}
|
||||
>
|
||||
{props.renderMenuItem(child as any, childIndex, {
|
||||
{props.renderMenuItem(child as unknown as T, childIndex, {
|
||||
selected: childIndex === submenu.selectedIndex,
|
||||
onClick: handleChildClick,
|
||||
})}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import some from "lodash/some";
|
||||
import { action, observable } from "mobx";
|
||||
import type { EditorState, Selection } from "prosemirror-state";
|
||||
import { NodeSelection, Plugin, TextSelection } from "prosemirror-state";
|
||||
@@ -82,12 +81,12 @@ export default class SelectionToolbarExtension extends Extension {
|
||||
return false;
|
||||
}
|
||||
|
||||
const slice = selection.content();
|
||||
const fragment = slice.content;
|
||||
const nodes = (fragment as any).content;
|
||||
const fragment = selection.content().content;
|
||||
|
||||
if (some(nodes, (n) => n.content.size)) {
|
||||
return selection;
|
||||
for (let i = 0; i < fragment.childCount; i++) {
|
||||
if (fragment.child(i).content.size) {
|
||||
return selection;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -28,9 +28,9 @@ export default class UpArrowAtStart extends Extension {
|
||||
const isAtDocStart = $pos.parentOffset === 0 && $pos.depth <= 1;
|
||||
|
||||
if (isAtDocStart) {
|
||||
// Call the onUpArrowAtStart callback if it exists
|
||||
// Cast to any to access the custom prop since it's not in the base Props type
|
||||
const props = this.editor.props as any;
|
||||
const props = this.editor.props as {
|
||||
onUpArrowAtStart?: () => void;
|
||||
};
|
||||
if (props.onUpArrowAtStart) {
|
||||
props.onUpArrowAtStart();
|
||||
return true;
|
||||
|
||||
+12
-7
@@ -38,7 +38,11 @@ import { basicExtensions as extensions } from "@shared/editor/nodes";
|
||||
import type Node from "@shared/editor/nodes/Node";
|
||||
import type ReactNode from "@shared/editor/nodes/ReactNode";
|
||||
import type { ComponentProps } from "@shared/editor/types";
|
||||
import type { ProsemirrorData, UserPreferences } from "@shared/types";
|
||||
import type {
|
||||
ProsemirrorData,
|
||||
ProsemirrorMark,
|
||||
UserPreferences,
|
||||
} from "@shared/types";
|
||||
import { ProsemirrorHelper } from "@shared/utils/ProsemirrorHelper";
|
||||
import EventEmitter from "@shared/utils/events";
|
||||
import type Document from "~/models/Document";
|
||||
@@ -117,7 +121,8 @@ export type Props = {
|
||||
/** Callback when user uses cancel key combo */
|
||||
onCancel?: () => void;
|
||||
/** Callback when user changes editor content */
|
||||
onChange?: (value: () => any) => void;
|
||||
// oxlint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
onChange?: (value: (asString?: boolean, trim?: boolean) => any) => void;
|
||||
/** Callback when a comment mark is clicked */
|
||||
onClickCommentMark?: (commentId: string) => void;
|
||||
/**
|
||||
@@ -755,9 +760,9 @@ export class Editor extends React.PureComponent<
|
||||
}
|
||||
|
||||
if (isArray(node.attrs?.marks)) {
|
||||
const existingMarks = node.attrs.marks;
|
||||
const existingMarks = node.attrs.marks as ProsemirrorMark[];
|
||||
const updatedMarks = existingMarks.filter(
|
||||
(mark: any) => mark.attrs.id !== commentId
|
||||
(mark) => mark.attrs?.id !== commentId
|
||||
);
|
||||
const attrs = {
|
||||
...node.attrs,
|
||||
@@ -800,9 +805,9 @@ export class Editor extends React.PureComponent<
|
||||
}
|
||||
|
||||
if (isArray(node.attrs?.marks)) {
|
||||
const existingMarks = node.attrs.marks;
|
||||
const updatedMarks = existingMarks.map((mark: any) =>
|
||||
mark.type === "comment" && mark.attrs.id === commentId
|
||||
const existingMarks = node.attrs.marks as ProsemirrorMark[];
|
||||
const updatedMarks = existingMarks.map((mark) =>
|
||||
mark.type === "comment" && mark.attrs?.id === commentId
|
||||
? { ...mark, attrs: { ...mark.attrs, ...attrs } }
|
||||
: mark
|
||||
);
|
||||
|
||||
@@ -14,6 +14,7 @@ import styled from "styled-components";
|
||||
import { s } from "@shared/styles";
|
||||
import { StatusFilter } from "@shared/types";
|
||||
import type Collection from "~/models/Collection";
|
||||
import type DocumentsStore from "~/stores/DocumentsStore";
|
||||
import CenteredContent from "~/components/CenteredContent";
|
||||
import { CollectionBreadcrumb } from "~/components/CollectionBreadcrumb";
|
||||
import Heading from "~/components/Heading";
|
||||
@@ -362,7 +363,13 @@ const Content = styled.div`
|
||||
`;
|
||||
|
||||
const RecentDocuments = observer(
|
||||
({ collection, documents }: { collection: Collection; documents: any }) => {
|
||||
({
|
||||
collection,
|
||||
documents,
|
||||
}: {
|
||||
collection: Collection;
|
||||
documents: DocumentsStore;
|
||||
}) => {
|
||||
useEffect(() => {
|
||||
void collection.fetchDocuments();
|
||||
}, [collection]);
|
||||
|
||||
@@ -15,6 +15,7 @@ import type { RefHandle } from "~/components/ContentEditable";
|
||||
import { useDocumentContext } from "~/components/DocumentContext";
|
||||
import type { Props as EditorProps } from "~/components/Editor";
|
||||
import Editor from "~/components/Editor";
|
||||
import type { Editor as SharedEditor } from "~/editor";
|
||||
import Flex from "~/components/Flex";
|
||||
import Time from "~/components/Time";
|
||||
import { withUIExtensions } from "~/editor/extensions";
|
||||
@@ -59,7 +60,8 @@ type Props = Omit<EditorProps, "editorStyle"> & {
|
||||
* The main document editor includes an editable title with metadata below it,
|
||||
* and support for commenting.
|
||||
*/
|
||||
function DocumentEditor(props: Props, ref: React.RefObject<any>) {
|
||||
function DocumentEditor(props: Props, ref: React.ForwardedRef<SharedEditor>) {
|
||||
const editorRef = React.useRef<SharedEditor>(null);
|
||||
const titleRef = React.useRef<RefHandle>(null);
|
||||
const { t } = useTranslation();
|
||||
const match = useRouteMatch();
|
||||
@@ -87,10 +89,10 @@ function DocumentEditor(props: Props, ref: React.RefObject<any>) {
|
||||
const iconColor = document.color ?? (first(colorPalette) as string);
|
||||
const childRef = React.useRef<HTMLDivElement>(null);
|
||||
const focusAtStart = React.useCallback(() => {
|
||||
if (ref.current) {
|
||||
ref.current.focusAtStart();
|
||||
if (editorRef.current) {
|
||||
editorRef.current.focusAtStart();
|
||||
}
|
||||
}, [ref]);
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (focusedComment && focusedComment.documentId === document.id) {
|
||||
@@ -113,15 +115,15 @@ function DocumentEditor(props: Props, ref: React.RefObject<any>) {
|
||||
|
||||
const handleGoToNextInput = React.useCallback(
|
||||
(insertParagraph: boolean) => {
|
||||
if (insertParagraph && ref.current) {
|
||||
const { view } = ref.current;
|
||||
if (insertParagraph && editorRef.current) {
|
||||
const { view } = editorRef.current;
|
||||
const { dispatch, state } = view;
|
||||
dispatch(state.tr.insert(0, state.schema.nodes.paragraph.create()));
|
||||
}
|
||||
|
||||
focusAtStart();
|
||||
},
|
||||
[focusAtStart, ref]
|
||||
[focusAtStart]
|
||||
);
|
||||
|
||||
// Create a Comment model in local store when a comment mark is created, this
|
||||
@@ -231,7 +233,7 @@ function DocumentEditor(props: Props, ref: React.RefObject<any>) {
|
||||
/>
|
||||
) : null}
|
||||
<EditorComponent
|
||||
ref={mergeRefs([ref, handleRefChanged])}
|
||||
ref={mergeRefs([ref, editorRef, handleRefChanged])}
|
||||
lang={getLangFor(document.language)}
|
||||
autoFocus={!!document.title && !props.defaultValue}
|
||||
placeholder={t("Type '/' to insert, or start writing…")}
|
||||
|
||||
@@ -13,8 +13,8 @@ type Item = Revision | Event<Document>;
|
||||
type Props = {
|
||||
items: Item[];
|
||||
document: Document;
|
||||
fetch: (options: Record<string, any> | undefined) => Promise<Item[]>;
|
||||
options?: Record<string, any>;
|
||||
fetch: (options: Record<string, unknown> | undefined) => Promise<Item[]>;
|
||||
options?: Record<string, unknown>;
|
||||
heading?: React.ReactNode;
|
||||
empty?: JSX.Element;
|
||||
};
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
useEffect,
|
||||
forwardRef,
|
||||
useRef,
|
||||
type ForwardedRef,
|
||||
} from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useHistory } from "react-router-dom";
|
||||
@@ -18,6 +19,7 @@ import EDITOR_VERSION from "@shared/editor/version";
|
||||
import { supportsPassiveListener } from "@shared/utils/browser";
|
||||
import type { Props as EditorProps } from "~/components/Editor";
|
||||
import Editor from "~/components/Editor";
|
||||
import type { Editor as SharedEditor } from "~/editor";
|
||||
import MultiplayerExtension from "~/editor/extensions/Multiplayer";
|
||||
import env from "~/env";
|
||||
import useCurrentUser from "~/hooks/useCurrentUser";
|
||||
@@ -50,7 +52,10 @@ type MessageEvent = {
|
||||
};
|
||||
};
|
||||
|
||||
function MultiplayerEditor({ onSynced, ...props }: Props, ref: any) {
|
||||
function MultiplayerEditor(
|
||||
{ onSynced, ...props }: Props,
|
||||
ref: ForwardedRef<SharedEditor>
|
||||
) {
|
||||
const documentId = props.id;
|
||||
const history = useHistory();
|
||||
const { t } = useTranslation();
|
||||
@@ -352,4 +357,4 @@ function MultiplayerEditor({ onSynced, ...props }: Props, ref: any) {
|
||||
);
|
||||
}
|
||||
|
||||
export default forwardRef<typeof MultiplayerEditor, Props>(MultiplayerEditor);
|
||||
export default forwardRef<SharedEditor, Props>(MultiplayerEditor);
|
||||
|
||||
+10
-24
@@ -1,6 +1,7 @@
|
||||
import data from "@emoji-mart/data";
|
||||
import type { EmojiMartData } from "@emoji-mart/data";
|
||||
import { Schema } from "prosemirror-model";
|
||||
import type { Editor } from "~/editor";
|
||||
import ExtensionManager from "@shared/editor/lib/ExtensionManager";
|
||||
import { populateEmojiData } from "@shared/editor/lib/emoji";
|
||||
import {
|
||||
@@ -12,6 +13,12 @@ import Mention from "@shared/editor/nodes/Mention";
|
||||
|
||||
populateEmojiData(data as EmojiMartData);
|
||||
|
||||
// Server-side parsing/serializing only requires schema and a few static props,
|
||||
// but the Extension API expects a full Editor. This stub satisfies bindEditor
|
||||
// without instantiating the React component.
|
||||
const stubEditor = (s: Schema): Editor =>
|
||||
({ schema: s, props: { theme: { isDark: false } } }) as unknown as Editor;
|
||||
|
||||
const extensions = withComments(richExtensions);
|
||||
export const extensionManager = new ExtensionManager(extensions);
|
||||
|
||||
@@ -21,14 +28,7 @@ export const schema = new Schema({
|
||||
});
|
||||
|
||||
for (const extension of extensionManager.extensions) {
|
||||
extension.bindEditor({
|
||||
schema,
|
||||
props: {
|
||||
theme: {
|
||||
isDark: false,
|
||||
},
|
||||
},
|
||||
} as any);
|
||||
extension.bindEditor(stubEditor(schema));
|
||||
}
|
||||
|
||||
export const parser = extensionManager.parser({
|
||||
@@ -48,14 +48,7 @@ export const basicSchema = new Schema({
|
||||
});
|
||||
|
||||
for (const extension of basicExtensionManager.extensions) {
|
||||
extension.bindEditor({
|
||||
schema: basicSchema,
|
||||
props: {
|
||||
theme: {
|
||||
isDark: false,
|
||||
},
|
||||
},
|
||||
} as any);
|
||||
extension.bindEditor(stubEditor(basicSchema));
|
||||
}
|
||||
|
||||
export const basicParser = basicExtensionManager.parser({
|
||||
@@ -72,14 +65,7 @@ export const commentSchema = new Schema({
|
||||
});
|
||||
|
||||
for (const extension of commentExtensionManager.extensions) {
|
||||
extension.bindEditor({
|
||||
schema: commentSchema,
|
||||
props: {
|
||||
theme: {
|
||||
isDark: false,
|
||||
},
|
||||
},
|
||||
} as any);
|
||||
extension.bindEditor(stubEditor(commentSchema));
|
||||
}
|
||||
|
||||
export const commentParser = commentExtensionManager.parser({
|
||||
|
||||
@@ -194,12 +194,11 @@ class Logger {
|
||||
// Errors have non-enumerable message/stack which are dropped by spreads
|
||||
// and JSON serialization, so convert them to a plain object up-front.
|
||||
if (input instanceof Error) {
|
||||
// oxlint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return {
|
||||
name: input.name,
|
||||
message: input.message,
|
||||
stack: input.stack,
|
||||
} as any as T;
|
||||
} as unknown as T;
|
||||
}
|
||||
|
||||
// Short circuit if we're not in production to enable easier debugging
|
||||
|
||||
@@ -14,6 +14,7 @@ function isExplicitlyNonReportable(error: Error): error is ReportableError {
|
||||
}
|
||||
|
||||
type PrivateDatadogContext = {
|
||||
// oxlint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
req: Record<string, any> & {
|
||||
_datadog?: {
|
||||
span?: Span;
|
||||
@@ -41,7 +42,10 @@ const getCurrentSpan = (): Span | null => tracer.scope().active();
|
||||
* @param tags An object with the tags to add to the span
|
||||
* @param span An optional span object to add the tags to. If none provided,the current span will be used.
|
||||
*/
|
||||
export function addTags(tags: Record<string, any>, span?: Span | null): void {
|
||||
export function addTags(
|
||||
tags: Parameters<Span["addTags"]>[0],
|
||||
span?: Span | null
|
||||
): void {
|
||||
if (tracer) {
|
||||
const currentSpan = span || getCurrentSpan();
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ class Event extends IdModel<
|
||||
* Note that the `data` column will be visible to the client and API requests.
|
||||
*/
|
||||
@Column(DataType.JSONB)
|
||||
// oxlint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
data: Record<string, any> | null;
|
||||
|
||||
/**
|
||||
@@ -67,6 +68,7 @@ class Event extends IdModel<
|
||||
* used for arbitrary data associated with the event.
|
||||
*/
|
||||
@Column(DataType.JSONB)
|
||||
// oxlint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
changes: Record<string, any> | null;
|
||||
|
||||
// hooks
|
||||
|
||||
@@ -757,7 +757,7 @@ export class ProsemirrorHelper extends SharedProsemirrorHelper {
|
||||
// Create a new document with the emoji removed from the text
|
||||
const json = doc.toJSON();
|
||||
|
||||
function removeEmojiFromNode(node: any): any {
|
||||
function removeEmojiFromNode(node: ProsemirrorData): ProsemirrorData {
|
||||
if (node.type === "text" && node.text && node.text.startsWith(emoji)) {
|
||||
return {
|
||||
...node,
|
||||
@@ -768,7 +768,7 @@ export class ProsemirrorHelper extends SharedProsemirrorHelper {
|
||||
let found = false;
|
||||
return {
|
||||
...node,
|
||||
content: node.content.map((child: any) => {
|
||||
content: node.content.map((child) => {
|
||||
if (found) {
|
||||
return child;
|
||||
}
|
||||
@@ -783,7 +783,7 @@ export class ProsemirrorHelper extends SharedProsemirrorHelper {
|
||||
return node;
|
||||
}
|
||||
|
||||
const modifiedJson = removeEmojiFromNode(json);
|
||||
const modifiedJson = removeEmojiFromNode(json as ProsemirrorData);
|
||||
return {
|
||||
emoji,
|
||||
doc: Node.fromJSON(schema, modifiedJson),
|
||||
@@ -798,7 +798,7 @@ export class ProsemirrorHelper extends SharedProsemirrorHelper {
|
||||
* @returns A cleanup function to restore the global environment.
|
||||
*/
|
||||
public static patchGlobalEnv(domWindow: JSDOM["window"]) {
|
||||
const g = global as any;
|
||||
const g = global as unknown as Record<string, unknown>;
|
||||
|
||||
const globalParams = {
|
||||
window: g.window,
|
||||
|
||||
@@ -3,7 +3,7 @@ import { BaseTask } from "./base/BaseTask";
|
||||
|
||||
type Props = {
|
||||
templateName: string;
|
||||
props: Record<string, any>;
|
||||
props: Record<string, unknown>;
|
||||
};
|
||||
|
||||
export default class EmailTask extends BaseTask<Props> {
|
||||
|
||||
@@ -56,7 +56,7 @@ export default function init(
|
||||
if (ioHandleUpgrade) {
|
||||
server.removeListener(
|
||||
"upgrade",
|
||||
ioHandleUpgrade as (...args: any[]) => void
|
||||
ioHandleUpgrade as (...args: unknown[]) => void
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -237,7 +237,8 @@ export function monkeyPatchSequelizeErrorsForJest(instance: Sequelize) {
|
||||
return instance;
|
||||
}
|
||||
|
||||
const sequelizeVersion = (Sequelize as any).version;
|
||||
const sequelizeVersion = (Sequelize as unknown as { version: string })
|
||||
.version;
|
||||
const major = sequelizeVersion.split(".").map(Number)[0];
|
||||
|
||||
if (major >= 7) {
|
||||
@@ -250,12 +251,13 @@ export function monkeyPatchSequelizeErrorsForJest(instance: Sequelize) {
|
||||
}
|
||||
|
||||
const origQueryFunc = instance.query.bind(instance);
|
||||
instance.query = (async (...args: any[]) => {
|
||||
instance.query = (async (...args: Parameters<typeof origQueryFunc>) => {
|
||||
try {
|
||||
return await origQueryFunc(...(args as Parameters<typeof origQueryFunc>));
|
||||
} catch (err: any) {
|
||||
return await origQueryFunc(...args);
|
||||
} catch (err) {
|
||||
// Ensure error appears in Jest output, not swallowed by Sequelize internals
|
||||
Logger.error(err.message, err.parent);
|
||||
const error = err as Error & { parent?: Error };
|
||||
Logger.error(error.message, error.parent ?? error);
|
||||
throw err;
|
||||
}
|
||||
}) as typeof instance.query;
|
||||
|
||||
@@ -86,6 +86,7 @@ export function error(err: unknown): CallToolResult {
|
||||
* @param handler - the handler function to wrap.
|
||||
* @returns the wrapped handler with tracing enabled.
|
||||
*/
|
||||
/* oxlint-disable @typescript-eslint/no-explicit-any */
|
||||
export function withTracing<F extends (...args: any[]) => any>(
|
||||
toolName: string,
|
||||
handler: F
|
||||
@@ -107,6 +108,7 @@ export function withTracing<F extends (...args: any[]) => any>(
|
||||
return handler.apply(this, args);
|
||||
} as F);
|
||||
}
|
||||
/* oxlint-enable @typescript-eslint/no-explicit-any */
|
||||
|
||||
/**
|
||||
* Builds a map from document ID to its zero-based index among siblings,
|
||||
|
||||
@@ -23,11 +23,14 @@ export async function getVersionInfo(currentVersion: string): Promise<{
|
||||
// Continue fetching pages until the required versions are found or no more pages
|
||||
while (nextUrl) {
|
||||
const response = await fetch(nextUrl);
|
||||
const data = await response.json();
|
||||
const data = (await response.json()) as {
|
||||
results: { name: string }[];
|
||||
next?: string | null;
|
||||
};
|
||||
|
||||
// Map and filter the versions to keep only full releases
|
||||
const pageVersions = data.results
|
||||
.map((result: any) => result.name)
|
||||
.map((result) => result.name)
|
||||
.filter(isFullReleaseVersion);
|
||||
|
||||
allVersions = allVersions.concat(pageVersions);
|
||||
|
||||
@@ -55,7 +55,11 @@ export function assertKeysIn(
|
||||
Object.keys(obj).forEach((key) => assertIn(key, Object.values(type)));
|
||||
}
|
||||
|
||||
export const assertSort = (value: string, model: any, message?: string) => {
|
||||
export const assertSort = (
|
||||
value: string,
|
||||
model: { rawAttributes: Record<string, unknown> },
|
||||
message?: string
|
||||
) => {
|
||||
if (!Object.keys(model.rawAttributes).includes(value)) {
|
||||
throw ValidationError(
|
||||
message ?? `${String(value)} is not a valid sort field`
|
||||
|
||||
@@ -13,9 +13,11 @@ export type WidgetProps = {
|
||||
};
|
||||
|
||||
export default class Extension {
|
||||
// oxlint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
options: any;
|
||||
editor: Editor;
|
||||
|
||||
// oxlint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
constructor(options: Record<string, any> = {}) {
|
||||
this.options = {
|
||||
...this.defaultOptions,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
const env = typeof window === "undefined" ? process.env : window.env;
|
||||
|
||||
// oxlint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export default env as Record<string, any>;
|
||||
|
||||
+6
-4
@@ -688,15 +688,17 @@ export type JSONValue =
|
||||
|
||||
export type JSONObject = { [x: string]: JSONValue };
|
||||
|
||||
export type ProsemirrorMark = {
|
||||
type: string;
|
||||
attrs?: JSONObject;
|
||||
};
|
||||
|
||||
export type ProsemirrorData = {
|
||||
type: string;
|
||||
content?: ProsemirrorData[];
|
||||
text?: string;
|
||||
attrs?: JSONObject;
|
||||
marks?: {
|
||||
type: string;
|
||||
attrs?: JSONObject;
|
||||
}[];
|
||||
marks?: ProsemirrorMark[];
|
||||
};
|
||||
|
||||
export type ProsemirrorDoc = {
|
||||
|
||||
Reference in New Issue
Block a user