diff --git a/app/scenes/Document/components/MultiplayerEditor.tsx b/app/scenes/Document/components/MultiplayerEditor.tsx index fc611ba12f..4042bafcee 100644 --- a/app/scenes/Document/components/MultiplayerEditor.tsx +++ b/app/scenes/Document/components/MultiplayerEditor.tsx @@ -59,8 +59,7 @@ function MultiplayerEditor({ onSynced, ...props }: Props, ref: any) { const { presence, auth, ui } = useStores(); const [editorVersionBehind, setEditorVersionBehind] = useState(false); const [showCursorNames, setShowCursorNames] = useState(false); - const [remoteProvider, setRemoteProvider] = - useState(null); + const [remoteProvider, setRemoteProvider] = useState(); const [hasLocalPersistence, setHasLocalPersistence] = useState(true); const [isLocalSynced, setLocalSynced] = useState(false); const [isRemoteSynced, setRemoteSynced] = useState(false); @@ -223,7 +222,7 @@ function MultiplayerEditor({ onSynced, ...props }: Props, ref: any) { window.removeEventListener("scroll", syncScrollPosition); provider?.destroy(); void localProvider?.destroy(); - setRemoteProvider(null); + setRemoteProvider(undefined); ui.setMultiplayerStatus(undefined, undefined); }; }, [ diff --git a/plugins/webhooks/server/tasks/DeliverWebhookTask.test.ts b/plugins/webhooks/server/tasks/DeliverWebhookTask.test.ts index e5e8b38bdd..63648a70a6 100644 --- a/plugins/webhooks/server/tasks/DeliverWebhookTask.test.ts +++ b/plugins/webhooks/server/tasks/DeliverWebhookTask.test.ts @@ -44,9 +44,7 @@ describe("DeliverWebhookTask", () => { "http://example.com", expect.anything() ); - const parsedBody = JSON.parse( - fetchMock.mock.calls[0]![1]!.body!.toString() - ); + const parsedBody = JSON.parse(fetchMock.mock.calls[0]![1]!.body as string); expect(parsedBody.webhookSubscriptionId).toBe(subscription.id); expect(parsedBody.event).toBe("users.signin"); expect(parsedBody.payload.id).toBe(signedInUser.id); @@ -120,9 +118,7 @@ describe("DeliverWebhookTask", () => { "http://example.com", expect.anything() ); - const parsedBody = JSON.parse( - fetchMock.mock.calls[0]![1]!.body!.toString() - ); + const parsedBody = JSON.parse(fetchMock.mock.calls[0]![1]!.body as string); expect(parsedBody.webhookSubscriptionId).toBe(subscription.id); expect(parsedBody.event).toBe("users.delete"); expect(parsedBody.payload.id).toBe(deletedUserId); diff --git a/server/__mocks__/bull.ts b/server/__mocks__/bull.ts index 33fc4cb323..aea7a2f13b 100644 --- a/server/__mocks__/bull.ts +++ b/server/__mocks__/bull.ts @@ -15,7 +15,7 @@ export default class Queue { return 0; } - add = function (data: any) { + add = function (data: unknown) { const job = this.createJob(data); if (!this.handler) { @@ -25,7 +25,7 @@ export default class Queue { this.handler(job, this.done); }; - process = function (handler: any) { + process = function (handler: (job: unknown, done: () => void) => void) { if (this.handler) { throw Error("Cannot define a handler more than once per Queue instance"); } @@ -33,7 +33,7 @@ export default class Queue { this.handler = handler; }; - createJob = function (data: any) { + createJob = function (data: unknown) { return { data, }; diff --git a/server/__mocks__/dd-trace.ts b/server/__mocks__/dd-trace.ts index a52277526d..3ef22ad55e 100644 --- a/server/__mocks__/dd-trace.ts +++ b/server/__mocks__/dd-trace.ts @@ -5,18 +5,18 @@ import type { Tracer } from "dd-trace"; const emptyFn = function () {}; const callableHandlers = { - get(_target: T, _prop: P, _receiver: any): T[P] { + get(_target: T, _prop: P, _receiver: unknown): T[P] { const newMock = new Proxy(emptyFn, callableHandlers); - return newMock as any as T[P]; + return newMock as unknown as T[P]; }, - apply any, A extends Parameters>( + apply unknown, A extends Parameters>( _target: T, - _thisArg: any, + _thisArg: unknown, _args: A ): ReturnType { const newMock = new Proxy(emptyFn, callableHandlers); - return newMock as any as ReturnType; + return newMock as unknown as ReturnType; }, }; @@ -31,7 +31,7 @@ export const mockTracer = new Proxy({} as MockTracer, { } if (key === "wrap") { - return (_: any, f: any) => f; + return (_: unknown, f: unknown) => f; } return callableMock; diff --git a/server/commands/userProvisioner.test.ts b/server/commands/userProvisioner.test.ts index fab6c2b7ae..eac4c3bb9d 100644 --- a/server/commands/userProvisioner.test.ts +++ b/server/commands/userProvisioner.test.ts @@ -308,10 +308,9 @@ describe("userProvisioner", () => { const authenticationProviders = await team.$get("authenticationProviders"); const authenticationProvider = authenticationProviders[0]; - let error; - try { - await userProvisioner(ctx, { + await expect( + userProvisioner(ctx, { name: "Uninvited User", email: "invite@ExamPle.com", teamId: team.id, @@ -321,14 +320,8 @@ describe("userProvisioner", () => { accessToken: "123", scopes: ["read"], }, - }); - } catch (err) { - error = err; - } - - expect(error && error.toString()).toContain( - "You need an invite to join this team" - ); + }) + ).rejects.toThrow("You need an invite to join this team"); }); it("should create a user from allowed domain", async () => { @@ -389,19 +382,14 @@ describe("userProvisioner", () => { it("should not create a user with emailMatchOnly when no allowed domains are set", async () => { const team = await buildTeam(); - let error; - try { - await userProvisioner(ctx, { + await expect( + userProvisioner(ctx, { name: "Test Name", email: faker.internet.email(), teamId: team.id, - }); - } catch (err) { - error = err; - } - - expect(error && error.toString()).toContain("UnauthorizedError"); + }) + ).rejects.toThrow("No matching user for email or allowed domain"); }); it("should reject an user when the domain is not allowed", async () => { @@ -415,10 +403,9 @@ describe("userProvisioner", () => { const authenticationProviders = await team.$get("authenticationProviders"); const authenticationProvider = authenticationProviders[0]; - let error; - try { - await userProvisioner(ctx, { + await expect( + userProvisioner(ctx, { name: "Bad Domain User", email: faker.internet.email(), teamId: team.id, @@ -428,13 +415,7 @@ describe("userProvisioner", () => { accessToken: "123", scopes: ["read"], }, - }); - } catch (err) { - error = err; - } - - expect(error && error.toString()).toContain( - "The domain is not allowed for this workspace" - ); + }) + ).rejects.toThrow("The domain is not allowed for this workspace"); }); }); diff --git a/server/logging/tracing.ts b/server/logging/tracing.ts index 17bdc05ee1..494ae15372 100644 --- a/server/logging/tracing.ts +++ b/server/logging/tracing.ts @@ -29,13 +29,14 @@ import * as Tracing from "./tracer"; type DDTag = (typeof DDTags)[keyof typeof DDTags]; type Tags = { - [tag in DDTag]?: any; + [tag in DDTag]?: unknown; } & { - [key: string]: any; + [key: string]: unknown; }; interface Constructor { - new (...args: any[]): any; + // oxlint-disable-next-line @typescript-eslint/no-explicit-any -- variance requires `any[]` to accept arbitrary constructors + new (...args: any[]): unknown; } interface TraceConfig { @@ -58,6 +59,7 @@ interface TraceConfig { export const traceFunction = (config: TraceConfig) => < + // oxlint-disable-next-line @typescript-eslint/no-explicit-any -- variance requires `any` to accept arbitrary functions F extends (...args: any[]) => any, P extends Parameters, R extends ReturnType, @@ -66,7 +68,7 @@ export const traceFunction = ): F => env.ENVIRONMENT === "test" ? target - : (function wrapperFn(this: any, ...args: P): R { + : (function wrapperFn(this: unknown, ...args: P): R { const { className, methodName = target.name, tags } = config; const childOf = config.isRoot ? undefined @@ -125,8 +127,8 @@ export const traceFunction = } as F); const traceMethod = (config?: TraceConfig) => - function R>( - target: any, + function R>( + target: { name?: string; constructor: { name: string } }, _propertyKey: string, descriptor: PropertyDescriptor ): TypedPropertyDescriptor { @@ -191,20 +193,24 @@ const traceClass = (config?: TraceConfig) => export function trace(config?: TraceConfig) { function traceDecorator(target: Constructor): void; function traceDecorator( - target: Record, + target: Record, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor ): void; function traceDecorator( - a: Constructor | Record, - b?: any, - c?: any + a: Constructor | Record, + b?: string | symbol, + c?: PropertyDescriptor ): void { if (typeof a === "function") { // Need to cast as there is no safe runtime way to check if a function is a constructor traceClass(config)(a as Constructor); } else { - traceMethod(config)(a, b, c); + traceMethod(config)( + a as { name?: string; constructor: { name: string } }, + b as string, + c! + ); } } diff --git a/server/policies/cancan.ts b/server/policies/cancan.ts index d541e63de6..be585560ac 100644 --- a/server/policies/cancan.ts +++ b/server/policies/cancan.ts @@ -2,14 +2,15 @@ import isObject from "lodash/isPlainObject"; import type { Model } from "sequelize-typescript"; import { AuthorizationError } from "@server/errors"; -type Constructor = new (...args: any) => any; +// oxlint-disable-next-line @typescript-eslint/no-explicit-any -- variance requires `any` to accept arbitrary constructors +type Constructor = new (...args: any[]) => unknown; type Policy = Record; type Condition = ( performer: InstanceType

, target: InstanceType | null, - options?: any + options?: unknown ) => boolean | string; type Ability = { @@ -132,7 +133,7 @@ export class CanCan { if (performer instanceof model) { for (const [action, abilities] of actionMap.entries()) { for (const ability of abilities) { - if (target instanceof (ability.target as any)) { + if (target instanceof (ability.target as Constructor)) { actionsToCheck.add(action); break; } @@ -211,7 +212,7 @@ export class CanCan { if ( ability.target === "all" || target === ability.target || - target instanceof (ability.target as any) + target instanceof (ability.target as Constructor) ) { matchingAbilities.push(ability); } @@ -225,7 +226,7 @@ export class CanCan { if ( ability.target === "all" || target === ability.target || - target instanceof (ability.target as any) + target instanceof (ability.target as Constructor) ) { matchingAbilities.push(ability); } diff --git a/server/queues/tasks/base/CronTask.test.ts b/server/queues/tasks/base/CronTask.test.ts index 9fcdd22c66..b1491c92f0 100644 --- a/server/queues/tasks/base/CronTask.test.ts +++ b/server/queues/tasks/base/CronTask.test.ts @@ -3,6 +3,8 @@ import { Minute } from "@shared/utils/time"; import type { PartitionInfo } from "./CronTask"; import { CronTask, TaskInterval } from "./CronTask"; +type RangeWhere = Record; + // Create a concrete implementation of CronTask for testing class TestTask extends CronTask { public async perform() { @@ -18,8 +20,8 @@ class TestTask extends CronTask { public testPartitionWhereClause( idField: string, partition: PartitionInfo | undefined - ) { - return this.getPartitionWhereClause(idField, partition); + ): RangeWhere { + return this.getPartitionWhereClause(idField, partition) as RangeWhere; } } @@ -105,7 +107,7 @@ describe("CronTask", () => { const where = task.testPartitionWhereClause("id", { partitionIndex: 0, partitionCount: 3, - }) as any; + }); expect(where).toBeDefined(); expect(where.id).toBeDefined(); @@ -117,17 +119,17 @@ describe("CronTask", () => { const where0 = task.testPartitionWhereClause("id", { partitionIndex: 0, partitionCount: 3, - }) as any; + }); const where1 = task.testPartitionWhereClause("id", { partitionIndex: 1, partitionCount: 3, - }) as any; + }); const where2 = task.testPartitionWhereClause("id", { partitionIndex: 2, partitionCount: 3, - }) as any; + }); // Partition 0: Should start from 00000000 expect(where0.id[Op.gte]).toBe("00000000-0000-4000-8000-000000000000"); @@ -146,12 +148,12 @@ describe("CronTask", () => { const where0 = task.testPartitionWhereClause("id", { partitionIndex: 0, partitionCount: 2, - }) as any; + }); const where1 = task.testPartitionWhereClause("id", { partitionIndex: 1, partitionCount: 2, - }) as any; + }); // Partition 0: 0x00000000 to 0x7fffffff expect(where0.id[Op.gte]).toBe("00000000-0000-4000-8000-000000000000"); @@ -170,7 +172,7 @@ describe("CronTask", () => { const where = task.testPartitionWhereClause("id", { partitionIndex: i, partitionCount, - }) as any; + }); ranges.push({ start: where.id[Op.gte], end: where.id[Op.lte], @@ -199,7 +201,7 @@ describe("CronTask", () => { const where = task.testPartitionWhereClause("id", { partitionIndex: 0, partitionCount: 1, - }) as any; + }); // Should cover entire UUID space expect(where.id[Op.gte]).toBe("00000000-0000-4000-8000-000000000000"); @@ -233,12 +235,12 @@ describe("CronTask", () => { const where1 = task.testPartitionWhereClause("id", { partitionIndex: 0, partitionCount: 2, - }) as any; + }); const where2 = task.testPartitionWhereClause("documentId", { partitionIndex: 0, partitionCount: 2, - }) as any; + }); expect(where1.id).toBeDefined(); expect(where1.documentId).toBeUndefined(); @@ -254,7 +256,7 @@ describe("CronTask", () => { const where = task.testPartitionWhereClause("id", { partitionIndex: i, partitionCount, - }) as any; + }); ranges.push({ start: where.id[Op.gte], end: where.id[Op.lte], @@ -276,7 +278,7 @@ describe("CronTask", () => { const where = task.testPartitionWhereClause("id", { partitionIndex: 1, partitionCount: 16, // 16 partitions = 0x10000000 per partition - }) as any; + }); // Partition 1 should be from 0x10000000 to 0x1fffffff expect(where.id[Op.gte]).toBe("10000000-0000-4000-8000-000000000000"); @@ -304,7 +306,7 @@ describe("CronTask", () => { const where = task.testPartitionWhereClause("id", { partitionIndex: i, partitionCount, - }) as any; + }); const startUuid = where.id[Op.gte]; const endUuid = where.id[Op.lte]; @@ -334,7 +336,7 @@ describe("CronTask", () => { const where = task.testPartitionWhereClause("id", { partitionIndex: i, partitionCount, - }) as any; + }); ranges.push({ start: where.id[Op.gte], end: where.id[Op.lte], diff --git a/server/queues/tasks/base/CronTask.ts b/server/queues/tasks/base/CronTask.ts index 635f59c8f9..cd126499f2 100644 --- a/server/queues/tasks/base/CronTask.ts +++ b/server/queues/tasks/base/CronTask.ts @@ -1,4 +1,4 @@ -import type { WhereOptions } from "sequelize"; +import type { WhereAttributeHash } from "sequelize"; import { Op } from "sequelize"; import { Minute } from "@shared/utils/time"; import { BaseTask } from "./BaseTask"; @@ -178,7 +178,7 @@ export abstract class CronTask extends BaseTask { protected getPartitionWhereClause( idField: string, partitionInfo: PartitionInfo | undefined - ): WhereOptions { + ): WhereAttributeHash { if (!partitionInfo) { return {}; } diff --git a/shared/editor/rules/checkboxes.ts b/shared/editor/rules/checkboxes.ts index 8efa10934f..8901270bc3 100644 --- a/shared/editor/rules/checkboxes.ts +++ b/shared/editor/rules/checkboxes.ts @@ -3,19 +3,19 @@ import type MarkdownIt from "markdown-it"; const CHECKBOX_REGEX = /\[(X|\s|_|-)\]\s(.*)?/i; -function matches(token: Token | undefined) { +function matches(token: Token) { return token && token.content.match(CHECKBOX_REGEX); } -function isInline(token: Token | undefined): boolean { +function isInline(token: Token): boolean { return !!token && token.type === "inline"; } -function isParagraph(token: Token | undefined): boolean { +function isParagraph(token: Token): boolean { return !!token && token.type === "paragraph_open"; } -function isListItem(token: Token | undefined): boolean { +function isListItem(token: Token): boolean { // Only match list_item_open, not checkbox_item_open - items that are already // checkbox_item_open have been processed (e.g., by the tables rule for // checkboxes in table cells) and should not be processed again.