chore: update eslint to 9.7.0 and stylelint to 16.7.0

This commit is contained in:
ryan-0324 2024-07-16 22:17:12 -04:00
parent 99d7ed0c08
commit 0c8e91b716
96 changed files with 689 additions and 1932 deletions

View file

@ -58,6 +58,7 @@
"@typescript-eslint/no-non-null-asserted-optional-chain": "error", "@typescript-eslint/no-non-null-asserted-optional-chain": "error",
"@typescript-eslint/no-unnecessary-condition": "error", "@typescript-eslint/no-unnecessary-condition": "error",
"@typescript-eslint/no-unnecessary-type-assertion": "error", "@typescript-eslint/no-unnecessary-type-assertion": "error",
"@typescript-eslint/no-unused-expressions": "error",
"@typescript-eslint/non-nullable-type-assertion-style": "error", "@typescript-eslint/non-nullable-type-assertion-style": "error",
"@typescript-eslint/prefer-as-const": "error", "@typescript-eslint/prefer-as-const": "error",
"@typescript-eslint/require-await": "error", "@typescript-eslint/require-await": "error",

View file

@ -1,7 +1,13 @@
{ {
"extends": "stylelint-config-standard", "extends": [
"stylelint-config-standard",
"@stylistic/stylelint-config"
],
"plugins": [
"@stylistic/stylelint-plugin"
],
"rules": { "rules": {
"indentation": 4, "@stylistic/indentation": 4,
"selector-class-pattern": [ "selector-class-pattern": [
"^[a-z][a-zA-Z0-9]*(-[a-z0-9][a-zA-Z0-9]*)*$", "^[a-z][a-zA-Z0-9]*(-[a-z0-9][a-zA-Z0-9]*)*$",
{ {

133
eslint.config.mjs Normal file
View file

@ -0,0 +1,133 @@
import stylistic from "@stylistic/eslint-plugin";
import pathAlias from "eslint-plugin-path-alias";
import simpleHeader from "eslint-plugin-simple-header";
import simpleImportSort from "eslint-plugin-simple-import-sort";
import unusedImports from "eslint-plugin-unused-imports";
import tseslint from "typescript-eslint";
export default tseslint.config(
{ ignores: ["browser", "dist", "packages", "src/**/*.?(c|m)js?(x)", "eslint.config.mjs"] },
{
files: ["**/*.?(c|m)[jt]s?(x)"],
languageOptions: {
parser: tseslint.parser,
parserOptions: {
projectService: true,
warnOnUnsupportedTypeScriptVersion: false
}
},
plugins: {
"@stylistic": stylistic,
"@typescript-eslint": tseslint.plugin,
"path-alias": pathAlias,
"simple-header": simpleHeader,
"simple-import-sort": simpleImportSort,
"unused-imports": unusedImports,
},
rules: {
// Since it's only been a month and Vencord has already been stolen
// by random skids who rebranded it to "AlphaCord" and erased all license
// information
"simple-header/header": ["error", {
files: ["scripts/header-new.txt", "scripts/header-old.txt"],
templates: { author: [".*", "Vendicated and contributors"] }
}],
"@stylistic/arrow-parens": ["error", "as-needed"],
"@stylistic/block-spacing": "error",
"@stylistic/eol-last": "error",
"@stylistic/func-call-spacing": "error",
"@stylistic/indent": ["error", 4, {
// Allow both flat and indented ternary expressions
ignoredNodes: [".consequent, .alternate, .trueType, .falseType"],
SwitchCase: 1
}],
"@stylistic/jsx-quotes": "error",
"@stylistic/linebreak-style": "error",
"@stylistic/member-delimiter-style": ["error", { singleline: { requireLast: true } }],
"@stylistic/no-extra-semi": "error",
"@stylistic/no-mixed-spaces-and-tabs": "error",
"@stylistic/no-multi-spaces": "error",
"@stylistic/no-trailing-spaces": "error",
"@stylistic/no-whitespace-before-property": "error",
"@stylistic/object-curly-spacing": ["error", "always"],
"@stylistic/quotes": ["error", "double", { avoidEscape: true }],
"@stylistic/semi": "error",
"@stylistic/semi-spacing": "error",
"@stylistic/semi-style": "error",
"@stylistic/space-before-function-paren": ["error", { named: "never" }],
"@stylistic/space-in-parens": "error",
"@stylistic/spaced-comment": ["error", "always", { markers: ["!"] }],
"@typescript-eslint/array-type": "error",
"@typescript-eslint/await-thenable": "error",
"@typescript-eslint/consistent-generic-constructors": "error",
"@typescript-eslint/consistent-type-assertions": ["error", {
assertionStyle: "as",
objectLiteralTypeAssertions: "allow-as-parameter"
}],
"@typescript-eslint/consistent-type-exports": ["error", {
fixMixedExportsWithInlineTypeSpecifier: true
}],
"@typescript-eslint/consistent-type-imports": ["error", {
disallowTypeAnnotations: false,
fixStyle: "inline-type-imports"
}],
"@typescript-eslint/no-confusing-void-expression": "error",
"@typescript-eslint/no-empty-object-type": "error",
"@typescript-eslint/no-extra-non-null-assertion": "error",
"@typescript-eslint/no-import-type-side-effects": "error",
"@typescript-eslint/no-loss-of-precision": "error",
"@typescript-eslint/no-non-null-asserted-nullish-coalescing": "error",
"@typescript-eslint/no-non-null-asserted-optional-chain": "error",
"@typescript-eslint/no-unnecessary-condition": "error",
"@typescript-eslint/no-unnecessary-type-assertion": "error",
"@typescript-eslint/no-unsafe-function-type": "error",
"@typescript-eslint/no-unused-expressions": "error",
"@typescript-eslint/no-wrapper-object-types": "error",
"@typescript-eslint/non-nullable-type-assertion-style": "error",
"@typescript-eslint/prefer-as-const": "error",
"@typescript-eslint/prefer-destructuring": "error",
"@typescript-eslint/require-await": "error",
"@typescript-eslint/return-await": "error",
"dot-notation": "error",
"eqeqeq": ["error", "always", { null: "ignore" }],
"for-direction": "error",
"no-async-promise-executor": "error",
"no-cond-assign": "error",
"no-constant-condition": ["error", { checkLoops: "none" }],
"no-dupe-else-if": "error",
"no-duplicate-case": "error",
"no-duplicate-imports": "error",
"no-fallthrough": "error",
"no-invalid-regexp": "error",
"no-irregular-whitespace": "error",
"no-misleading-character-class": "error",
"no-prototype-builtins": "error",
"no-regex-spaces": "error",
"no-restricted-globals": ["error", "_", "Diff", "JSX", "React", "ReactDOM"],
"no-restricted-imports": ["error", {
patterns: [{
regex: "^discord-types(/|$)",
message: "Use @vencord/discord-types instead."
}]
}],
"no-restricted-syntax": ["error", "[operator=void]"],
"no-shadow-restricted-names": "error",
"no-unexpected-multiline": "error",
"no-unneeded-ternary": ["error", { defaultAssignment: false }],
"no-unsafe-optional-chaining": "error",
"no-useless-backreference": "error",
"no-useless-computed-key": "error",
"no-useless-escape": ["error", { extra: "i" }],
"operator-assignment": "error",
"path-alias/no-relative": "error",
"prefer-const": "error",
"prefer-object-spread": "error",
"prefer-spread": "error",
"simple-import-sort/exports": "error",
"simple-import-sort/imports": "error",
"unused-imports/no-unused-imports": "error",
"use-isnan": "error",
"yoda": "error",
}
},
);

View file

@ -26,8 +26,8 @@
"generateTypes": "tspc --emitDeclarationOnly --declaration --outDir packages/vencord-types", "generateTypes": "tspc --emitDeclarationOnly --declaration --outDir packages/vencord-types",
"inject": "node scripts/runInstaller.mjs", "inject": "node scripts/runInstaller.mjs",
"uninject": "node scripts/runInstaller.mjs", "uninject": "node scripts/runInstaller.mjs",
"lint": "eslint . --ext .mjs,.js,.jsx,.mts,.ts,.tsx --ignore-pattern src/userplugins", "lint": "eslint . --ignore-pattern src/userplugins",
"lint-styles": "stylelint \"src/**/*.css\" --ignore-pattern src/userplugins --quiet-deprecation-warnings", "lint-styles": "stylelint \"src/**/*.css\" --ignore-pattern src/userplugins",
"lint:fix": "pnpm lint --fix", "lint:fix": "pnpm lint --fix",
"test": "pnpm buildStandalone && pnpm lint && pnpm lint-styles && pnpm testTsc && pnpm generatePluginJson", "test": "pnpm buildStandalone && pnpm lint && pnpm lint-styles && pnpm testTsc && pnpm generatePluginJson",
"testWeb": "pnpm lint && pnpm buildWeb && pnpm testTsc", "testWeb": "pnpm lint && pnpm buildWeb && pnpm testTsc",
@ -45,6 +45,9 @@
"virtual-merge": "^1.0.1" "virtual-merge": "^1.0.1"
}, },
"devDependencies": { "devDependencies": {
"@stylistic/eslint-plugin": "^2.3.0",
"@stylistic/stylelint-config": "^1.0.1",
"@stylistic/stylelint-plugin": "^2.1.2",
"@types/chrome": "^0.0.268", "@types/chrome": "^0.0.268",
"@types/diff": "^5.2.1", "@types/diff": "^5.2.1",
"@types/html-minifier-terser": "^7.0.2", "@types/html-minifier-terser": "^7.0.2",
@ -53,28 +56,26 @@
"@types/react": "~18.2.79", "@types/react": "~18.2.79",
"@types/react-dom": "~18.2.25", "@types/react-dom": "~18.2.25",
"@types/yazl": "^2.4.5", "@types/yazl": "^2.4.5",
"@typescript-eslint/eslint-plugin": "^7.16.1",
"@typescript-eslint/parser": "^7.16.1",
"@vencord/discord-types": "workspace:^", "@vencord/discord-types": "workspace:^",
"diff": "^5.2.0", "diff": "^5.2.0",
"discord-types": "^1.3.3", "discord-types": "^1.3.3",
"esbuild": "^0.23.0", "esbuild": "^0.23.0",
"eslint": "^8.57.0", "eslint": "^9.7.0",
"eslint-import-resolver-alias": "^1.1.2",
"eslint-plugin-path-alias": "^2.1.0", "eslint-plugin-path-alias": "^2.1.0",
"eslint-plugin-simple-import-sort": "^12.1.1", "eslint-plugin-simple-import-sort": "^12.1.1",
"eslint-plugin-unused-imports": "^3.2.0", "eslint-plugin-unused-imports": "^4.0.0",
"highlight.js": "11.8.0", "highlight.js": "11.8.0",
"html-minifier-terser": "^7.2.0", "html-minifier-terser": "^7.2.0",
"moment": "2.22.2", "moment": "2.22.2",
"puppeteer-core": "^22.13.0", "puppeteer-core": "^22.13.0",
"standalone-electron-types": "^1.0.0", "standalone-electron-types": "^1.0.0",
"stylelint": "^15.11.0", "stylelint": "^16.7.0",
"stylelint-config-standard": "^33.0.0", "stylelint-config-standard": "^36.0.1",
"ts-patch": "^3.2.1", "ts-patch": "^3.2.1",
"tsx": "^4.16.2", "tsx": "^4.16.2",
"type-fest": "^4.21.0", "type-fest": "^4.21.0",
"typescript": "^5.5.3", "typescript": "^5.5.3",
"typescript-eslint": "^8.0.0-alpha.44",
"typescript-transform-paths": "^3.4.7", "typescript-transform-paths": "^3.4.7",
"zip-local": "^0.3.5" "zip-local": "^0.3.5"
}, },
@ -82,13 +83,12 @@
"pnpm": { "pnpm": {
"patchedDependencies": { "patchedDependencies": {
"eslint-plugin-path-alias@2.1.0": "patches/eslint-plugin-path-alias@2.1.0.patch", "eslint-plugin-path-alias@2.1.0": "patches/eslint-plugin-path-alias@2.1.0.patch",
"eslint@8.57.0": "patches/eslint@8.57.0.patch" "eslint@9.7.0": "patches/eslint@9.7.0.patch"
}, },
"peerDependencyRules": { "peerDependencyRules": {
"ignoreMissing": [ "allowedVersions": {
"eslint-plugin-import", "eslint": "9"
"eslint" }
]
}, },
"allowedDeprecatedVersions": { "allowedDeprecatedVersions": {
"source-map-resolve": "*", "source-map-resolve": "*",

View file

@ -158,7 +158,7 @@ export default tseslint.config(
}, },
{ {
files: ["**/*"], files: ["**/*"],
ignores: ["src/**/*"], ignores: ["src/**"],
rules: { rules: {
"simple-import-sort/imports": ["error", { "simple-import-sort/imports": ["error", {
groups: [ groups: [
@ -169,7 +169,7 @@ export default tseslint.config(
} }
}, },
{ {
files: ["scripts/**/*", "src/**/*"], files: ["scripts/**", "src/**"],
rules: { rules: {
"headers/header-format": ["error", { "headers/header-format": ["error", {
source: "string", source: "string",
@ -188,7 +188,7 @@ export default tseslint.config(
} }
}, },
{ {
files: ["src/**/*"], files: ["src/**"],
rules: { rules: {
"@typescript-eslint/member-ordering": ["error", { "@typescript-eslint/member-ordering": ["error", {
default: { default: {
@ -243,7 +243,7 @@ export default tseslint.config(
}, },
{ {
// https://github.com/import-js/eslint-plugin-import/issues/2414 // https://github.com/import-js/eslint-plugin-import/issues/2414
files: ["src/**/*"], files: ["src/**"],
ignores: ["src/**/index.ts"], ignores: ["src/**/index.ts"],
rules: { rules: {
"import/no-unused-modules": ["error", { missingExports: true }], "import/no-unused-modules": ["error", { missingExports: true }],

File diff suppressed because it is too large Load diff

View file

@ -18,9 +18,7 @@
/* eslint-disable no-fallthrough */ /* eslint-disable no-fallthrough */
// eslint-disable-next-line spaced-comment
/// <reference types="../src/globals.d.ts" /> /// <reference types="../src/globals.d.ts" />
// eslint-disable-next-line spaced-comment
/// <reference types="../src/modules.d.ts" /> /// <reference types="../src/modules.d.ts" />
import { readFileSync } from "fs"; import { readFileSync } from "fs";

View file

@ -12,7 +12,6 @@
"checkJs": true, "checkJs": true,
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"target": "ESNext" "target": "ESNext"
}, },

View file

@ -85,9 +85,10 @@ export function _getBadges(args: BadgeUserArgs) {
}) })
: [{ ...badge, ...args }]; : [{ ...badge, ...args }];
badge.position === BadgePosition.START if (badge.position === BadgePosition.START)
? badges.unshift(...b) badges.unshift(...b);
: badges.push(...b); else
badges.push(...b);
} }
} }
const donorBadges = (Plugins.BadgeAPI as unknown as typeof import("../plugins/_api/badges").default).getDonorBadges(args.userId); const donorBadges = (Plugins.BadgeAPI as unknown as typeof import("../plugins/_api/badges").default).getDonorBadges(args.userId);

View file

@ -14,7 +14,7 @@ import { Button, ButtonLooks, ButtonWrapperClasses, Tooltip } from "@webpack/com
import type { HTMLProps, JSX, MouseEventHandler, ReactNode } from "react"; import type { HTMLProps, JSX, MouseEventHandler, ReactNode } from "react";
let ChannelTextAreaClasses: Record<"button" | "buttonContainer", string> | undefined; let ChannelTextAreaClasses: Record<"button" | "buttonContainer", string> | undefined;
waitFor(["buttonContainer", "channelTextArea"], m => ChannelTextAreaClasses = m); waitFor(["buttonContainer", "channelTextArea"], m => { ChannelTextAreaClasses = m; });
export interface ChatBarProps { export interface ChatBarProps {
channel: ChannelRecord; channel: ChannelRecord;
@ -24,52 +24,52 @@ export interface ChatBarProps {
analyticsName: string; analyticsName: string;
attachments: boolean; attachments: boolean;
autocomplete: { autocomplete: {
addReactionShortcut: boolean, addReactionShortcut: boolean;
forceChatLayer: boolean, forceChatLayer: boolean;
reactions: boolean; reactions: boolean;
}, };
commands: { commands: {
enabled: boolean; enabled: boolean;
}, };
drafts: { drafts: {
type: number, type: number;
commandType: number, commandType: number;
autoSave: boolean; autoSave: boolean;
}, };
emojis: { emojis: {
button: boolean; button: boolean;
}, };
gifs: { gifs: {
button: boolean, button: boolean;
allowSending: boolean; allowSending: boolean;
}, };
gifts: { gifts: {
button: boolean; button: boolean;
}, };
permissions: { permissions: {
requireSendMessages: boolean; requireSendMessages: boolean;
}, };
showThreadPromptOnReply: boolean, showThreadPromptOnReply: boolean;
stickers: { stickers: {
button: boolean, button: boolean;
allowSending: boolean, allowSending: boolean;
autoSuggest: boolean; autoSuggest: boolean;
}, };
users: { users: {
allowMentioning: boolean; allowMentioning: boolean;
}, };
submit: { submit: {
button: boolean, button: boolean;
ignorePreference: boolean, ignorePreference: boolean;
disableEnterToSubmit: boolean, disableEnterToSubmit: boolean;
clearOnSubmit: boolean, clearOnSubmit: boolean;
useDisabledStylesOnSubmit: boolean; useDisabledStylesOnSubmit: boolean;
}, };
uploadLongMessages: boolean, uploadLongMessages: boolean;
upsellLongMessages: { upsellLongMessages: {
iconOnly: boolean; iconOnly: boolean;
}, };
showCharacterCount: boolean, showCharacterCount: boolean;
sedReplace: boolean; sedReplace: boolean;
}; };
} }

View file

@ -42,7 +42,7 @@ interface DecoratorProps {
export type Decorator = (props: DecoratorProps) => JSX.Element | null; export type Decorator = (props: DecoratorProps) => JSX.Element | null;
type OnlyIn = "guilds" | "dms"; type OnlyIn = "guilds" | "dms";
export const decorators = new Map<string, { decorator: Decorator, onlyIn?: OnlyIn; }>(); export const decorators = new Map<string, { decorator: Decorator; onlyIn?: OnlyIn; }>();
export function addDecorator(identifier: string, decorator: Decorator, onlyIn?: OnlyIn) { export function addDecorator(identifier: string, decorator: Decorator, onlyIn?: OnlyIn) {
decorators.set(identifier, { decorator, onlyIn }); decorators.set(identifier, { decorator, onlyIn });

View file

@ -24,7 +24,7 @@ import type { Promisable } from "type-fest";
const MessageEventsLogger = new Logger("MessageEvents", "#e5c890"); const MessageEventsLogger = new Logger("MessageEvents", "#e5c890");
export interface MessageObject { export interface MessageObject {
content: string, content: string;
validNonShortcutEmojis: GuildEmoji[]; validNonShortcutEmojis: GuildEmoji[];
invalidEmojis: any[]; invalidEmojis: any[];
tts: boolean; tts: boolean;

View file

@ -19,7 +19,7 @@
import { waitFor } from "@webpack"; import { waitFor } from "@webpack";
let NoticesModule: any; let NoticesModule: any;
waitFor(m => m.show && m.dismiss && !m.suppressAll, m => NoticesModule = m); waitFor(m => m.show && m.dismiss && !m.suppressAll, m => { NoticesModule = m; });
export const noticesQueue: any[] = []; export const noticesQueue: any[] = [];
export let currentNotice: any = null; export let currentNotice: any = null;

View file

@ -136,7 +136,7 @@ function NotificationEntry({ data }: { data: PersistentNotificationData; }) {
); );
} }
export function NotificationLog({ log, pending }: { log: PersistentNotificationData[], pending: boolean; }) { export function NotificationLog({ log, pending }: { log: PersistentNotificationData[]; pending: boolean; }) {
if (!log.length && !pending) if (!log.length && !pending)
return ( return (
<div className={cl("container")}> <div className={cl("container")}>

View file

@ -30,7 +30,7 @@ import plugins from "~plugins";
const logger = new Logger("Settings"); const logger = new Logger("Settings");
export interface Settings { export interface Settings {
autoUpdate: boolean; autoUpdate: boolean;
autoUpdateNotification: boolean, autoUpdateNotification: boolean;
useQuickCss: boolean; useQuickCss: boolean;
enableReactDevtools: boolean; enableReactDevtools: boolean;
themeLinks: string[]; themeLinks: string[];
@ -250,11 +250,12 @@ export function definePluginSettings<
type UseSettings<T extends object> = ResolveUseSettings<T>[keyof T]; type UseSettings<T extends object> = ResolveUseSettings<T>[keyof T];
type ResolveUseSettings<T extends object> = { type ResolveUseSettings<T extends object> = {
[Key in keyof T]: [Key in keyof T]: Key extends string
Key extends string ? T[Key] extends Record<string, unknown>
? T[Key] extends Record<string, unknown> ? UseSettings<T[Key]> extends string
// @ts-ignore "Type instantiation is excessively deep and possibly infinite" // @ts-ignore "Type instantiation is excessively deep and possibly infinite"
? UseSettings<T[Key]> extends string ? `${Key}.${UseSettings<T[Key]>}` : never ? `${Key}.${UseSettings<T[Key]>}`
: Key : never
: never; : Key
: never;
}; };

View file

@ -12,7 +12,7 @@ const CodeContainerClasses: Record<string, string> = findByPropsLazy("markup", "
/** /**
* Renders code in a Discord codeblock * Renders code in a Discord codeblock
*/ */
export const CodeBlock = (props: { content?: string, lang: string; }) => ( export const CodeBlock = (props: { content?: string; lang: string; }) => (
<div className={CodeContainerClasses.markup}> <div className={CodeContainerClasses.markup}>
{MarkupUtils.defaultRules.codeBlock!.react(props, null, {})} {MarkupUtils.defaultRules.codeBlock!.react(props, null, {})}
</div> </div>

View file

@ -30,7 +30,7 @@ interface Props<T = any> {
/** Fallback component to render if an error occurs */ /** Fallback component to render if an error occurs */
fallback?: ComponentType<PropsWithChildren<{ error: any; message: string; stack: string; }>>; fallback?: ComponentType<PropsWithChildren<{ error: any; message: string; stack: string; }>>;
/** called when an error occurs. The props property is only available if using .wrap */ /** called when an error occurs. The props property is only available if using .wrap */
onError?(data: { error: Error, errorInfo: ErrorInfo, props: T; }): void; onError?(data: { error: Error; errorInfo: ErrorInfo; props: T; }): void;
/** Custom error message */ /** Custom error message */
message?: string; message?: string;

View file

@ -3,7 +3,7 @@
width: 32px; width: 32px;
border-radius: 50%; border-radius: 50%;
border: 4px solid var(--background-tertiary); border: 4px solid var(--background-tertiary);
box-sizing: border-box box-sizing: border-box;
} }
.vc-settings-modal-links { .vc-settings-modal-links {

View file

@ -190,7 +190,12 @@ function ReplacementInput({ replacement, setReplacement, replacementError }: Rep
} }
useEffect( useEffect(
() => { (isFunc ? onChange(replacement) : setError(undefined)); }, () => {
if (isFunc)
onChange(replacement);
else
setError(undefined);
},
[isFunc] [isFunc]
); );

View file

@ -134,8 +134,10 @@ const ThemeCard = ({ theme, enabled, onChange, onDelete }: ThemeCardProps) => (
href={`https://discord.gg/${theme.invite}`} href={`https://discord.gg/${theme.invite}`}
onClick={e => { onClick={e => {
e.preventDefault(); e.preventDefault();
theme.invite != null && openInviteModal(theme.invite) if (theme.invite != null)
.catch(() => { showToast("Invalid or expired invite"); }); openInviteModal(theme.invite).catch(() => {
showToast("Invalid or expired invite");
});
}} }}
> >
Discord Server Discord Server

View file

@ -77,7 +77,7 @@ interface CommonProps {
repoPending: boolean; repoPending: boolean;
} }
const HashLink = ({ repo, hash, disabled = false }: { repo: string, hash: string, disabled?: boolean; }) => ( const HashLink = ({ repo, hash, disabled = false }: { repo: string; hash: string; disabled?: boolean; }) => (
<Link href={`${repo}/commit/${hash}`} disabled={disabled}> <Link href={`${repo}/commit/${hash}`} disabled={disabled}>
{hash} {hash}
</Link> </Link>

View file

@ -51,7 +51,7 @@ if (!IS_VANILLA) {
const originalBuild = Menu.buildFromTemplate; const originalBuild = Menu.buildFromTemplate;
Menu.buildFromTemplate = function (template) { Menu.buildFromTemplate = function (template) {
if (template[0]?.label === "&File") { if (template[0]?.label === "&File") {
const { submenu } = template[0]; const [{ submenu }] = template;
if (Array.isArray(submenu)) { if (Array.isArray(submenu)) {
submenu.push({ submenu.push({
label: "Quit (Hidden)", label: "Quit (Hidden)",

1
src/modules.d.ts vendored
View file

@ -16,7 +16,6 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
// eslint-disable-next-line spaced-comment
/// <reference types="standalone-electron-types"/> /// <reference types="standalone-electron-types"/>
declare module "~plugins" { declare module "~plugins" {

View file

@ -49,9 +49,9 @@ interface RemoteData {
artistArtwork?: string; artistArtwork?: string;
} }
let cachedRemoteData: { id: string, data: RemoteData; } | { id: string, failures: number; } | null = null; let cachedRemoteData: { id: string; data: RemoteData; } | { id: string; failures: number; } | null = null;
async function fetchRemoteData({ id, name, artist, album }: { id: string, name: string, artist: string, album: string; }) { async function fetchRemoteData({ id, name, artist, album }: { id: string; name: string; artist: string; album: string; }) {
if (id === cachedRemoteData?.id) { if (id === cachedRemoteData?.id) {
if ("data" in cachedRemoteData) return cachedRemoteData.data; if ("data" in cachedRemoteData) return cachedRemoteData.data;
if ("failures" in cachedRemoteData && cachedRemoteData.failures >= 5) return null; if ("failures" in cachedRemoteData && cachedRemoteData.failures >= 5) return null;

View file

@ -11,7 +11,7 @@ import type { Dispatch, SetStateAction } from "react";
import type { Session } from "../types"; import type { Session } from "../types";
import { RenameModal } from "./RenameModal"; import { RenameModal } from "./RenameModal";
export const RenameButton = ({ session, state }: { session: Session, state: [string, Dispatch<SetStateAction<string>>]; }) => ( export const RenameButton = ({ session, state }: { session: Session; state: [string, Dispatch<SetStateAction<string>>]; }) => (
<Button <Button
look={Button.Looks.LINK} look={Button.Looks.LINK}
color={Button.Colors.LINK} color={Button.Colors.LINK}

View file

@ -23,7 +23,7 @@ import type { Dispatch, KeyboardEvent, SetStateAction } from "react";
import type { Session } from "../types"; import type { Session } from "../types";
import { getDefaultName, savedSessionsCache, saveSessionsToDataStore } from "../utils"; import { getDefaultName, savedSessionsCache, saveSessionsToDataStore } from "../utils";
export function RenameModal({ props, session, state }: { props: ModalProps, session: Session, state: [string, Dispatch<SetStateAction<string>>]; }) { export function RenameModal({ props, session, state }: { props: ModalProps; session: Session; state: [string, Dispatch<SetStateAction<string>>]; }) {
const [title, setTitle] = state; const [title, setTitle] = state;
const [value, setValue] = useState(savedSessionsCache.get(session.id_hash)?.name ?? ""); const [value, setValue] = useState(savedSessionsCache.get(session.id_hash)?.name ?? "");

View file

@ -107,7 +107,7 @@ export default definePlugin({
); );
}, { noop: true }), }, { noop: true }),
renderTimestamp: ErrorBoundary.wrap(({ session, timeLabel }: { session: Session, timeLabel: string; }) => ( renderTimestamp: ErrorBoundary.wrap(({ session, timeLabel }: { session: Session; timeLabel: string; }) => (
<Tooltip <Tooltip
text={session.approx_last_used_time.toLocaleString()} text={session.approx_last_used_time.toLocaleString()}
tooltipClassName={TimestampClasses.timestampTooltip} tooltipClassName={TimestampClasses.timestampTooltip}
@ -120,7 +120,7 @@ export default definePlugin({
</Tooltip> </Tooltip>
), { noop: true }), ), { noop: true }),
renderIcon: ErrorBoundary.wrap(({ session, DeviceIcon }: { session: Session, DeviceIcon: ComponentType<any>; }) => { renderIcon: ErrorBoundary.wrap(({ session, DeviceIcon }: { session: Session; DeviceIcon: ComponentType<any>; }) => {
const PlatformIcon = GetPlatformIcon(session.client_info.platform); const PlatformIcon = GetPlatformIcon(session.client_info.platform);
return ( return (

View file

@ -25,7 +25,7 @@ export interface SessionInfo {
platform: string; platform: string;
location: string; location: string;
}; };
}, };
current?: boolean; current?: boolean;
} }

View file

@ -17,7 +17,7 @@ type SettingsEntry = { section: string; label: string; };
const cl = classNameFactory(""); const cl = classNameFactory("");
let Classes: Record<string, string>; let Classes: Record<string, string>;
waitFor(["animating", "baseLayer", "bg", "layer", "layers"], m => Classes = m); waitFor(["animating", "baseLayer", "bg", "layer", "layers"], m => { Classes = m; });
const settings = definePluginSettings({ const settings = definePluginSettings({
disableFade: { disableFade: {

View file

@ -36,14 +36,14 @@ export interface Stream extends ApplicationStream {
} }
export interface RTCStream { export interface RTCStream {
region: string, region: string;
streamKey: string, streamKey: string;
viewerIds: string[]; viewerIds: string[];
} }
export interface StreamMetadata { export interface StreamMetadata {
id: string | null, id: string | null;
pid: number | null, pid: number | null;
sourceName: string | null; sourceName: string | null;
} }

View file

@ -26,7 +26,7 @@
.client-theme-contrast-warning { .client-theme-contrast-warning {
background-color: var(--background-primary); background-color: var(--background-primary);
padding: 0.5rem; padding: 0.5rem;
border-radius: .5rem; border-radius: 0.5rem;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: space-between; justify-content: space-between;

View file

@ -55,7 +55,7 @@ export default definePlugin({
settings, settings,
contextMenus: { contextMenus: {
"expression-picker"(children, { target }: { target: Target }) { "expression-picker"(children, { target }: { target: Target; }) {
if (target.dataset.type !== "emoji") return; if (target.dataset.type !== "emoji") return;
children.push( children.push(

View file

@ -2,7 +2,8 @@
filter: grayscale(1); filter: grayscale(1);
} }
.vc-dearrow-toggle-on, .vc-dearrow-toggle-off { .vc-dearrow-toggle-on,
.vc-dearrow-toggle-off {
all: unset; all: unset;
display: inline; display: inline;
cursor: pointer; cursor: pointer;

View file

@ -31,7 +31,7 @@ interface UsersDecorationsState {
export const useUsersDecorationsStore: { export const useUsersDecorationsStore: {
(): UsersDecorationsState; (): UsersDecorationsState;
getState: () => UsersDecorationsState getState: () => UsersDecorationsState;
subscribe: (handler: (state: UsersDecorationsState) => void) => () => void; subscribe: (handler: (state: UsersDecorationsState) => void) => () => void;
} = proxyLazy(() => zustandCreate((set: any, get: any): UsersDecorationsState => ({ } = proxyLazy(() => zustandCreate((set: any, get: any): UsersDecorationsState => ({
usersDecorations: new Map<string, UserDecorationData>(), usersDecorations: new Map<string, UserDecorationData>(),

View file

@ -10,8 +10,8 @@ import { React } from "@webpack/common";
import type { ComponentType, HTMLProps, PropsWithChildren } from "react"; import type { ComponentType, HTMLProps, PropsWithChildren } from "react";
type DecorationGridItemComponent = ComponentType<PropsWithChildren<HTMLProps<HTMLDivElement>> & { type DecorationGridItemComponent = ComponentType<PropsWithChildren<HTMLProps<HTMLDivElement>> & {
onSelect: () => void, onSelect: () => void;
isSelected: boolean, isSelected: boolean;
}>; }>;
export let DecorationGridItem: DecorationGridItemComponent; export let DecorationGridItem: DecorationGridItemComponent;
@ -24,8 +24,8 @@ export const AvatarDecorationModalPreview = LazyComponentWebpack(() => {
type DecorationGridDecorationComponent = ComponentType<HTMLProps<HTMLDivElement> & { type DecorationGridDecorationComponent = ComponentType<HTMLProps<HTMLDivElement> & {
avatarDecoration: AvatarDecorationData; avatarDecoration: AvatarDecorationData;
onSelect: () => void, onSelect: () => void;
isSelected: boolean, isSelected: boolean;
}>; }>;
export let DecorationGridDecoration: DecorationGridDecorationComponent; export let DecorationGridDecoration: DecorationGridDecorationComponent;

View file

@ -98,11 +98,12 @@ function initWs(isManual = false) {
logger.info("Connected to WebSocket"); logger.info("Connected to WebSocket");
(settings.store.notifyOnAutoConnect || isManual) && showNotification({ if (settings.store.notifyOnAutoConnect || isManual)
title: "Dev Companion Connected", showNotification({
body: "Connected to WebSocket", title: "Dev Companion Connected",
noPersist: true body: "Connected to WebSocket",
}); noPersist: true
});
}); });
ws.addEventListener("error", e => { ws.addEventListener("error", e => {

View file

@ -153,7 +153,7 @@ async function doClone(guildId: string, data: Data) {
} catch (e: any) { } catch (e: any) {
let message = "Something went wrong (check console!)"; let message = "Something went wrong (check console!)";
try { try {
message = JSON.parse(e.text).message; ({ message } = JSON.parse(e.text));
} catch { } } catch { }
new Logger("EmoteCloner").error("Failed to clone", data.name, "to", guildId, e); new Logger("EmoteCloner").error("Failed to clone", data.name, "to", guildId, e);

View file

@ -426,8 +426,8 @@ export default definePlugin({
}, },
handleGradientThemeSelect(backgroundGradientPresetId: number | undefined, theme: number, original: () => void) { handleGradientThemeSelect(backgroundGradientPresetId: number | undefined, theme: number, original: () => void) {
const premiumType = UserStore.getCurrentUser()?.premiumType ?? 0; const premiumType = UserStore.getCurrentUser()?.premiumType;
if (premiumType === 2 || backgroundGradientPresetId == null) { if (premiumType === UserPremiumType.TIER_2 || backgroundGradientPresetId == null) {
original(); original();
return; return;
} }
@ -466,37 +466,41 @@ export default definePlugin({
}, },
trimContent(content: any[]) { trimContent(content: any[]) {
const firstContent = content[0]; const [firstContent] = content;
if (typeof firstContent === "string") { if (typeof firstContent === "string") {
content[0] = firstContent.trimStart(); content[0] = firstContent.trimStart();
content[0] || content.shift(); if (!content[0]) content.shift();
} else if (typeof firstContent?.props?.children === "string") { } else if (typeof firstContent?.props?.children === "string") {
firstContent.props.children = firstContent.props.children.trimStart(); firstContent.props.children = firstContent.props.children.trimStart();
firstContent.props.children || content.shift(); if (!firstContent.props.children) content.shift();
} }
const lastIndex = content.length - 1; const lastIndex = content.length - 1;
const lastContent = content[lastIndex]; const lastContent = content[lastIndex];
if (typeof lastContent === "string") { if (typeof lastContent === "string") {
content[lastIndex] = lastContent.trimEnd(); content[lastIndex] = lastContent.trimEnd();
content[lastIndex] || content.pop(); if (!content[lastIndex]) content.pop();
} else if (typeof lastContent?.props?.children === "string") { } else if (typeof lastContent?.props?.children === "string") {
lastContent.props.children = lastContent.props.children.trimEnd(); lastContent.props.children = lastContent.props.children.trimEnd();
lastContent.props.children || content.pop(); if (!lastContent.props.children) content.pop();
} }
}, },
clearEmptyArrayItems(array: any[]) { clearEmptyArrayItems<T>(array: T[]) {
return array.filter(item => item != null); return array.filter(item => item != null);
}, },
ensureChildrenIsArray(child: ReactElement) { ensureChildrenIsArray(child: ReactElement) {
if (!Array.isArray(child.props.children)) child.props.children = [child.props.children]; if (!Array.isArray(child.props.children))
child.props.children = [child.props.children];
}, },
patchFakeNitroEmojisOrRemoveStickersLinks(content: any[], inline: boolean) { patchFakeNitroEmojisOrRemoveStickersLinks(content: any[], inline: boolean) {
// If content has more than one child or it's a single ReactElement like a header, list or span // If content has more than one child or it's a single ReactElement like a header, list or span
if ((content.length > 1 || typeof content[0]?.type === "string") && !settings.store.transformCompoundSentence) return content; if (
(content.length > 1 || typeof content[0]?.type === "string")
&& !settings.store.transformCompoundSentence
) return content;
let nextIndex = content.length; let nextIndex = content.length;
@ -509,7 +513,8 @@ export default definePlugin({
url = new URL(child.props.href); url = new URL(child.props.href);
} catch { } } catch { }
const emojiName = EmojiStore.getCustomEmojiById(fakeNitroMatch[1])?.name ?? url?.searchParams.get("name") ?? "FakeNitroEmoji"; const emojiName = EmojiStore.getCustomEmojiById(fakeNitroMatch[1])?.name
?? url?.searchParams.get("name") ?? "FakeNitroEmoji";
return MarkupUtils.defaultRules.customEmoji!.react({ return MarkupUtils.defaultRules.customEmoji!.react({
jumboable: !inline && content.length === 1 && typeof content[0].type !== "string", jumboable: !inline && content.length === 1 && typeof content[0].type !== "string",
@ -603,10 +608,16 @@ export default definePlugin({
if (settings.store.transformCompoundSentence) itemsToMaybePush.push(...contentItems); if (settings.store.transformCompoundSentence) itemsToMaybePush.push(...contentItems);
else if (contentItems.length === 1) itemsToMaybePush.push(contentItems[0]!); else if (contentItems.length === 1) itemsToMaybePush.push(contentItems[0]!);
itemsToMaybePush.push(...message.attachments.filter(attachment => attachment.content_type === "image/gif").map(attachment => attachment.url)); itemsToMaybePush.push(...message.attachments
.filter(attachment => attachment.content_type === "image/gif")
.map(attachment => attachment.url));
for (const item of itemsToMaybePush) { for (const item of itemsToMaybePush) {
if (!settings.store.transformCompoundSentence && !item.startsWith("http") && !hyperLinkRegex.test(item)) continue; if (
!settings.store.transformCompoundSentence
&& !item.startsWith("http")
&& !hyperLinkRegex.test(item)
) continue;
const imgMatch = item.match(fakeNitroStickerRegex); const imgMatch = item.match(fakeNitroStickerRegex);
if (imgMatch) { if (imgMatch) {
@ -615,7 +626,8 @@ export default definePlugin({
url = new URL(item); url = new URL(item);
} catch { } } catch { }
const stickerName = StickerStore.getStickerById(imgMatch[1]!)?.name ?? url?.searchParams.get("name") ?? "FakeNitroSticker"; const stickerName = StickerStore.getStickerById(imgMatch[1]!)?.name
?? url?.searchParams.get("name") ?? "FakeNitroSticker";
stickers.push({ stickers.push({
format_type: StickerFormat.PNG, format_type: StickerFormat.PNG,
id: imgMatch[1], id: imgMatch[1],
@ -693,19 +705,19 @@ export default definePlugin({
return link.target && fakeNitroEmojiRegex.test(link.target); return link.target && fakeNitroEmojiRegex.test(link.target);
}, },
addFakeNotice(type: FakeNoticeType, node: ReactNode[], fake: boolean) { addFakeNotice(type: FakeNoticeType, node: ReactNode, fake: boolean) {
if (!fake) return node; if (!fake) return node;
node = Array.isArray(node) ? node : [node]; const nodeArray: ReactNode[] = Array.isArray(node) ? node : [node];
switch (type) { switch (type) {
case FakeNoticeType.Sticker: { case FakeNoticeType.Sticker: {
node.push(" This is a FakeNitro sticker and renders like a real sticker only for you. Appears as a link to non-plugin users."); nodeArray.push(" This is a FakeNitro sticker and renders like a real sticker only for you. Appears as a link to non-plugin users.");
return node; return node;
} }
case FakeNoticeType.Emoji: { case FakeNoticeType.Emoji: {
node.push(" This is a FakeNitro emoji and renders like a real emoji only for you. Appears as a link to non-plugin users."); nodeArray.push(" This is a FakeNitro emoji and renders like a real emoji only for you. Appears as a link to non-plugin users.");
return node; return node;
} }

View file

@ -53,10 +53,10 @@ interface Instance {
resultType?: string; resultType?: string;
}; };
props: { props: {
favCopy: Gif[], favCopy: Gif[];
favorites: Gif[], favorites: Gif[];
}, };
forceUpdate: () => void; forceUpdate: () => void;
} }

View file

@ -34,7 +34,7 @@ export default definePlugin({
} }
} }
], ],
isGuildOwner(props: { user?: UserRecord, channel?: ChannelRecord, isOwner: boolean, guildId?: string; }) { isGuildOwner(props: { user?: UserRecord; channel?: ChannelRecord; isOwner: boolean; guildId?: string; }) {
if (!props.user?.id) return props.isOwner; if (!props.user?.id) return props.isOwner;
if (props.channel?.type === ChannelType.GROUP_DM) if (props.channel?.type === ChannelType.GROUP_DM)
return props.isOwner; return props.isOwner;

View file

@ -70,7 +70,7 @@ function greet(channel: ChannelRecord, message: MessageRecord, stickers: string[
} }
function GreetMenu({ channel, message }: { message: MessageRecord, channel: ChannelRecord; }) { function GreetMenu({ channel, message }: { message: MessageRecord; channel: ChannelRecord; }) {
const s = settings.use(["greetMode", "multiGreetChoices"]); const s = settings.use(["greetMode", "multiGreetChoices"]);
const { greetMode, multiGreetChoices = [] } = s; const { greetMode, multiGreetChoices = [] } = s;
@ -172,7 +172,7 @@ export default definePlugin({
pickSticker( pickSticker(
event: UIEvent, event: UIEvent,
props: { props: {
channel: ChannelRecord, channel: ChannelRecord;
message: MessageRecord & { deleted?: boolean; }; message: MessageRecord & { deleted?: boolean; };
} }
) { ) {

View file

@ -303,7 +303,7 @@ export default definePlugin({
return true; return true;
}, },
renderToggleGameActivityButton: (props: { id?: string; name: string, exePath: string; }, nowPlaying: boolean) => ( renderToggleGameActivityButton: (props: { id?: string; name: string; exePath: string; }, nowPlaying: boolean) => (
<ErrorBoundary noop> <ErrorBoundary noop>
<div style={{ marginLeft: 12, zIndex: 0 }}> <div style={{ marginLeft: 12, zIndex: 0 }}>
{ToggleActivityComponent({ id: props.id ?? props.exePath, name: props.name, type: ActivitiesTypes.Game }, nowPlaying)} {ToggleActivityComponent({ id: props.id ?? props.exePath, name: props.name, type: ActivitiesTypes.Game }, nowPlaying)}

View file

@ -25,13 +25,13 @@ import { settings } from "../index";
import { waitFor } from "../utils/waitFor"; import { waitFor } from "../utils/waitFor";
interface Vec2 { interface Vec2 {
x: number, x: number;
y: number; y: number;
} }
export interface MagnifierProps { export interface MagnifierProps {
zoom: number; zoom: number;
size: number, size: number;
instance: any; instance: any;
} }

View file

@ -261,7 +261,7 @@ export default definePlugin({
stop() { stop() {
disableStyle(styles); disableStyle(styles);
// so componenetWillUnMount gets called if Magnifier component is still alive // so componenetWillUnMount gets called if Magnifier component is still alive
this.root && this.root.unmount(); if (this.root) this.root.unmount();
this.element?.remove(); this.element?.remove();
} }
}); });

View file

@ -18,7 +18,7 @@
border-radius: 0; border-radius: 0;
} }
.vc-imgzoom-nearest-neighbor>img { .vc-imgzoom-nearest-neighbor > img {
image-rendering: pixelated; image-rendering: pixelated;
/* https://googlechrome.github.io/samples/image-rendering-pixelated/index.html */ /* https://googlechrome.github.io/samples/image-rendering-pixelated/index.html */

View file

@ -40,7 +40,7 @@ export const OnlineMemberCountStore = proxyLazy(() => {
} }
return new OnlineMemberCountStore(FluxDispatcher, { return new OnlineMemberCountStore(FluxDispatcher, {
GUILD_MEMBER_LIST_UPDATE({ guildId, groups }: { guildId: string, groups: { count: number; id: string; }[]; }) { GUILD_MEMBER_LIST_UPDATE({ guildId, groups }: { guildId: string; groups: { count: number; id: string; }[]; }) {
onlineMemberMap.set( onlineMemberMap.set(
guildId, guildId,
groups.reduce((total, curr) => total + (curr.id === StatusType.OFFLINE ? 0 : curr.count), 0) groups.reduce((total, curr) => total + (curr.id === StatusType.OFFLINE ? 0 : curr.count), 0)

View file

@ -25,7 +25,7 @@ export default definePlugin({
} }
}], }],
renderUsername: ErrorBoundary.wrap((props: { user?: UserRecord, username: string; }) => { renderUsername: ErrorBoundary.wrap((props: { user?: UserRecord; username: string; }) => {
const { user, username } = props; const { user, username } = props;
const [isHovering, setIsHovering] = useState(false); const [isHovering, setIsHovering] = useState(false);

View file

@ -18,9 +18,9 @@ type Fill = [FillValue, FillValue, FillValue];
type DiffKey = keyof Diff; type DiffKey = keyof Diff;
interface Diff { interface Diff {
days: number, days: number;
hours: number, hours: number;
minutes: number, minutes: number;
seconds: number; seconds: number;
milliseconds: number; milliseconds: number;
} }
@ -172,7 +172,7 @@ export default definePlugin({
Icon({ delta, fill, props }: { Icon({ delta, fill, props }: {
delta: string | null; delta: string | null;
fill: Fill, fill: Fill;
props: { props: {
onClick: () => void; onClick: () => void;
onMouseEnter: () => void; onMouseEnter: () => void;

View file

@ -255,7 +255,7 @@ export default definePlugin({
}, },
}, },
handleDelete(channelMessages: ChannelMessages | null | undefined, data: { ids: string[], id: string; mlDeleted?: boolean; }, isBulk: boolean) { handleDelete(channelMessages: ChannelMessages | null | undefined, data: { ids: string[]; id: string; mlDeleted?: boolean; }, isBulk: boolean) {
try { try {
if (channelMessages == null || (!isBulk && !channelMessages.has(data.id))) if (channelMessages == null || (!isBulk && !channelMessages.has(data.id)))
return channelMessages; return channelMessages;

View file

@ -2,8 +2,9 @@
display: none; display: none;
} }
.messagelogger-deleted /* https://github.com/stylelint-stylistic/stylelint-stylistic/issues/30 */
:is( /* stylelint-disable @stylistic/indentation */
.messagelogger-deleted:is(
video, video,
.emoji, .emoji,
[data-type="sticker"], [data-type="sticker"],
@ -11,6 +12,7 @@
.messagelogger-deleted-attachment, .messagelogger-deleted-attachment,
[class|="inlineMediaEmbed"] [class|="inlineMediaEmbed"]
) { ) {
/* stylelint-enable @stylistic/indentation */
filter: grayscale(1) !important; filter: grayscale(1) !important;
transition: 150ms filter ease-in-out; transition: 150ms filter ease-in-out;
@ -19,8 +21,9 @@
} }
} }
.messagelogger-deleted /* https://github.com/stylelint-stylistic/stylelint-stylistic/issues/30 */
:is( /* stylelint-disable @stylistic/indentation */
.messagelogger-deleted:is(
video, video,
.emoji, .emoji,
[data-type="sticker"], [data-type="sticker"],
@ -28,6 +31,7 @@
.messagelogger-deleted-attachment, .messagelogger-deleted-attachment,
[class|="inlineMediaEmbed"] [class|="inlineMediaEmbed"]
):hover { ):hover {
/* stylelint-enable @stylistic/indentation */
filter: grayscale(0) !important; filter: grayscale(0) !important;
} }

View file

@ -61,7 +61,7 @@ const computePermissions: (options: {
excludeGuildPermissions?: boolean /* = false */; excludeGuildPermissions?: boolean /* = false */;
}) => bigint = findByCodeLazy(".getCurrentUser()", ".computeLurkerPermissionsAllowList()"); }) => bigint = findByCodeLazy(".getCurrentUser()", ".computeLurkerPermissionsAllowList()");
const Tag: RC<{ type?: number, className?: string, useRemSizes?: boolean; }> & { Types: Record<string, number>; } const Tag: RC<{ type?: number; className?: string; useRemSizes?: boolean; }> & { Types: Record<string, number>; }
= findLazy(m => m.Types?.[0] === "BOT"); = findLazy(m => m.Types?.[0] === "BOT");
const isWebhook = (message: MessageRecord | undefined, user: UserRecord) => !!message?.webhookId && user.isNonUserBot(); const isWebhook = (message: MessageRecord | undefined, user: UserRecord) => !!message?.webhookId && user.isNonUserBot();
@ -332,9 +332,9 @@ export default definePlugin({
getTag({ getTag({
message, user, channelId, origType, location, channel message, user, channelId, origType, location, channel
}: { }: {
message?: MessageRecord, message?: MessageRecord;
user?: UserRecord, user?: UserRecord;
channel?: ChannelRecord, channel?: ChannelRecord;
channelId?: string; channelId?: string;
origType?: number; origType?: number;
location: "chat" | "not-chat"; location: "chat" | "not-chat";

View file

@ -76,7 +76,7 @@ export default definePlugin({
isBotOrMe: (user: UserRecord) => user.bot || user.id === UserStore.getCurrentUser()!.id, isBotOrMe: (user: UserRecord) => user.bot || user.id === UserStore.getCurrentUser()!.id,
renderMutualGDMs: ErrorBoundary.wrap(({ user, onClose }: { user: UserRecord, onClose: () => void; }) => { renderMutualGDMs: ErrorBoundary.wrap(({ user, onClose }: { user: UserRecord; onClose: () => void; }) => {
const entries = ChannelStore.getSortedPrivateChannels() const entries = ChannelStore.getSortedPrivateChannels()
.filter((channel): channel is GroupDMChannelRecord => .filter((channel): channel is GroupDMChannelRecord =>
channel.isGroupDM() channel.isGroupDM()

View file

@ -78,7 +78,7 @@ const settings = definePluginSettings({
}); });
const makeContextMenuPatch = (shouldAddIcon: boolean) => const makeContextMenuPatch = (shouldAddIcon: boolean) =>
((children, { guild }: { guild?: GuildRecord, onClose: () => void; }) => { ((children, { guild }: { guild?: GuildRecord; onClose: () => void; }) => {
if (!guild) return; if (!guild) return;
const group = findGroupChildrenByChildId("privacy", children); const group = findGroupChildrenByChildId("privacy", children);

View file

@ -160,10 +160,10 @@
width: -moz-fit-content; width: -moz-fit-content;
width: fit-content; width: fit-content;
height: 24px; height: 24px;
padding: 4px padding: 4px;
} }
.custom-profile-theme .vc-permviewer-role-button { .custom-profile-theme .vc-permviewer-role-button {
background: rgb(var(--bg-overlay-color)/var(--bg-overlay-opacity-6)); background: rgb(var(--bg-overlay-color) / var(--bg-overlay-opacity-6));
border-color: var(--profile-body-border-color) border-color: var(--profile-body-border-color);
} }

View file

@ -23,8 +23,8 @@ import { DEFAULT_CHUNK_SIZE } from "./constants";
import { canMoveCategory, canMoveCategoryInDirection, categories, type Category, categoryLen, collapseCategory, getAllUncollapsedChannels, getSections, init, isPinned, moveCategory, removeCategory } from "./data"; import { canMoveCategory, canMoveCategoryInDirection, categories, type Category, categoryLen, collapseCategory, getAllUncollapsedChannels, getSections, init, isPinned, moveCategory, removeCategory } from "./data";
interface ChannelComponentProps { interface ChannelComponentProps {
children: ReactNode, children: ReactNode;
channel: ChannelRecord, channel: ChannelRecord;
selected: boolean; selected: boolean;
} }

View file

@ -6,7 +6,7 @@
text-transform: uppercase; text-transform: uppercase;
font-size: 12px; font-size: 12px;
line-height: 16px; line-height: 16px;
letter-spacing: .02em; letter-spacing: 0.02em;
font-family: var(--font-display); font-family: var(--font-display);
font-weight: 600; font-weight: 600;
flex: 1 1 auto; flex: 1 1 auto;
@ -29,7 +29,7 @@
width: 16px; width: 16px;
height: 16px; height: 16px;
color: var(--interactive-normal); color: var(--interactive-normal);
transform: rotate(90deg) transform: rotate(90deg);
} }
.vc-pindms-collapsed .vc-pindms-collapse-icon { .vc-pindms-collapsed .vc-pindms-collapse-icon {

View file

@ -71,7 +71,7 @@ const Icons = {
const StatusUtils = findByPropsLazy("useStatusFillColor", "StatusTypes"); const StatusUtils = findByPropsLazy("useStatusFillColor", "StatusTypes");
const PlatformIcon = ({ platform, status, small }: { platform: ClientType, status: StatusType; small: boolean; }) => { const PlatformIcon = ({ platform, status, small }: { platform: ClientType; status: StatusType; small: boolean; }) => {
const tooltip = platform === ClientType.EMBEDDED const tooltip = platform === ClientType.EMBEDDED
? "Console" ? "Console"
: platform[0]!.toUpperCase() + platform.slice(1); : platform[0]!.toUpperCase() + platform.slice(1);

View file

@ -28,7 +28,7 @@ const UploadAttachmentStore: FluxStore & Record<string, any> = findStoreLazy("Up
const getDraft = (channelId: string) => DraftStore.getDraft(channelId, DraftType.CHANNEL_MESSAGE); const getDraft = (channelId: string) => DraftStore.getDraft(channelId, DraftType.CHANNEL_MESSAGE);
const getImageBox = (url: string): Promise<{ width: number, height: number; } | null> => const getImageBox = (url: string): Promise<{ width: number; height: number; } | null> =>
new Promise(res => { new Promise(res => {
const img = new Image(); const img = new Image();
img.onload = () => { img.onload = () => {

View file

@ -149,11 +149,11 @@ async function bulkFetchPronouns(ids: string[]): Promise<PronounsResponse> {
const SpecialCodes = new Set(["any", "ask", "avoid", "other", "unspecified"]); const SpecialCodes = new Set(["any", "ask", "avoid", "other", "unspecified"]);
export function extractPronouns(pronounSet?: { [locale: string]: PronounCode[] }): string { export function extractPronouns(pronounSet?: { [locale: string]: PronounCode[]; }): string {
if (!pronounSet || !pronounSet.en) return PronounMapping.unspecified; if (!pronounSet || !pronounSet.en) return PronounMapping.unspecified;
// PronounDB returns an empty set instead of {sets: {en: ["unspecified"]}}. // PronounDB returns an empty set instead of {sets: {en: ["unspecified"]}}.
const pronouns = pronounSet.en; const pronouns = pronounSet.en;
const { pronounsFormat } = Settings.plugins.PronounDB as { pronounsFormat: PronounsFormat, enabled: boolean; }; const { pronounsFormat } = Settings.plugins.PronounDB as { pronounsFormat: PronounsFormat; enabled: boolean; };
if (pronouns.length === 1) { if (pronouns.length === 1) {
// For capitalized pronouns or special codes (any, ask, avoid), we always return the normal (capitalized) string // For capitalized pronouns or special codes (any, ask, avoid), we always return the normal (capitalized) string

View file

@ -29,14 +29,14 @@ export interface PronounsResponse {
[id: string]: { [id: string]: {
sets?: { sets?: {
[locale: string]: PronounCode[]; [locale: string]: PronounCode[];
} };
} };
} }
export interface CachePronouns { export interface CachePronouns {
sets?: { sets?: {
[locale: string]: PronounCode[]; [locale: string]: PronounCode[];
} };
} }
export type PronounCode = keyof typeof PronounMapping; export type PronounCode = keyof typeof PronounMapping;

View file

@ -44,7 +44,7 @@ function ReplyTimestamp({
referencedMessage, referencedMessage,
baseMessage, baseMessage,
}: { }: {
referencedMessage: ReferencedMessage, referencedMessage: ReferencedMessage;
baseMessage: MessageRecord; baseMessage: MessageRecord;
}) { }) {
if (referencedMessage.state !== ReferencedMessageState.LOADED) return null; if (referencedMessage.state !== ReferencedMessageState.LOADED) return null;

View file

@ -83,18 +83,18 @@ export interface ReviewDBCurrentUser extends ReviewDBUser {
} }
export interface ReviewAuthor { export interface ReviewAuthor {
id: number, id: number;
discordID: string, discordID: string;
username: string, username: string;
profilePhoto: string, profilePhoto: string;
badges: Badge[]; badges: Badge[];
} }
export interface Review { export interface Review {
comment: string, comment: string;
id: number, id: number;
star: number, star: number;
sender: ReviewAuthor, sender: ReviewAuthor;
timestamp: number; timestamp: number;
type?: ReviewType; type?: ReviewType;
} }

View file

@ -51,7 +51,7 @@ const guildPopoutPatch = ((children, { guild }: { guild?: GuildRecord; onClose:
); );
}) satisfies NavContextMenuPatchCallback; }) satisfies NavContextMenuPatchCallback;
const userContextPatch = ((children, { user }: { user?: UserRecord, onClose(): void; }) => { const userContextPatch = ((children, { user }: { user?: UserRecord; onClose(): void; }) => {
if (user) if (user)
children.push( children.push(
<Menu.MenuItem <Menu.MenuItem

View file

@ -78,9 +78,10 @@ export default definePlugin({
// idk if this is good for performance but it doesnt seem to be a problem in my experience // idk if this is good for performance but it doesnt seem to be a problem in my experience
DataStore.update("summaries-data", summaries => { DataStore.update("summaries-data", summaries => {
summaries ??= {}; summaries ??= {};
summaries[data.channel_id] if (summaries[data.channel_id])
? summaries[data.channel_id].unshift(...incomingSummaries) summaries[data.channel_id].unshift(...incomingSummaries);
: (summaries[data.channel_id] = incomingSummaries); else
summaries[data.channel_id] = incomingSummaries;
if (summaries[data.channel_id].length > 50) if (summaries[data.channel_id].length > 50)
summaries[data.channel_id] = summaries[data.channel_id].slice(0, 50); summaries[data.channel_id] = summaries[data.channel_id].slice(0, 50);

View file

@ -54,7 +54,7 @@ type Format = typeof Formats[number];
const cl = classNameFactory("vc-st-"); const cl = classNameFactory("vc-st-");
function PickerModal({ rootProps, close }: { rootProps: ModalProps, close(): void; }) { function PickerModal({ rootProps, close }: { rootProps: ModalProps; close(): void; }) {
const [value, setValue] = useState<string>(); const [value, setValue] = useState<string>();
const [format, setFormat] = useState<Format>(""); const [format, setFormat] = useState<Format>("");
const time = Math.round((new Date(value!).getTime() || Date.now()) / 1000); const time = Math.round((new Date(value!).getTime() || Date.now()) / 1000);

View file

@ -28,7 +28,7 @@ export interface Language {
name: string; name: string;
id: string; id: string;
devicon?: string; devicon?: string;
grammarUrl: string, grammarUrl: string;
grammar?: ILanguageRegistration["grammar"]; grammar?: ILanguageRegistration["grammar"];
scopeName: string; scopeName: string;
aliases?: string[]; aliases?: string[];

View file

@ -21,8 +21,8 @@ import type { Dispatch, SetStateAction } from "react";
type Shiki = typeof import("../api/shiki").shiki; type Shiki = typeof import("../api/shiki").shiki;
interface ThemeState { interface ThemeState {
id: Shiki["currentThemeUrl"], id: Shiki["currentThemeUrl"];
theme: Shiki["currentTheme"], theme: Shiki["currentTheme"];
} }
const currentTheme: ThemeState = { const currentTheme: ThemeState = {

View file

@ -7,8 +7,8 @@ async function handleClick() {
} }
export const Example: FC<{ export const Example: FC<{
real: boolean, real: boolean;
shigged?: number, shigged?: number;
}> = ({ real, shigged }) => ( }> = ({ real, shigged }) => (
<> <>
<p>{`Shigg${real ? `ies${shigged === 0x1B ? "t" : ""}` : "y"}`}</p> <p>{`Shigg${real ? `ies${shigged === 0x1B ? "t" : ""}` : "y"}`}</p>

View file

@ -29,8 +29,8 @@ export const shouldUseHljs = ({
lang, lang,
tryHljs, tryHljs,
}: { }: {
lang: HighlighterProps["lang"], lang: HighlighterProps["lang"];
tryHljs: HljsSetting, tryHljs: HljsSetting;
}) => { }) => {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
const hljsLang = lang ? hljs?.getLanguage?.(lang) : null; const hljsLang = lang ? hljs?.getLanguage?.(lang) : null;

View file

@ -95,7 +95,7 @@ const profilePanelComponent = ErrorBoundary.wrap(
{ noop: true } { noop: true }
); );
function ConnectionsComponent({ id, theme, simplified }: { id: string, theme: string, simplified?: boolean; }) { function ConnectionsComponent({ id, theme, simplified }: { id: string; theme: string; simplified?: boolean; }) {
const profile = UserProfileStore.getUserProfile(id); const profile = UserProfileStore.getUserProfile(id);
if (!profile) if (!profile)
return null; return null;
@ -131,7 +131,7 @@ function ConnectionsComponent({ id, theme, simplified }: { id: string, theme: st
); );
} }
function CompactConnectionComponent({ connection, theme }: { connection: ProfileConnectedAccountData, theme: string; }) { function CompactConnectionComponent({ connection, theme }: { connection: ProfileConnectedAccountData; theme: string; }) {
const platform = Platforms.get(useLegacyPlatformType(connection.type)); const platform = Platforms.get(useLegacyPlatformType(connection.type));
const url = platform.getPlatformUserUrl?.(connection); const url = platform.getPlatformUserUrl?.(connection);

View file

@ -162,7 +162,7 @@ function SeekBar() {
const [position, setPosition] = useState<number>(storePosition); const [position, setPosition] = useState<number>(storePosition);
// eslint-disable-next-line consistent-return
useEffect(() => { useEffect(() => {
if (isPlaying && !isSettingPosition) { if (isPlaying && !isSettingPosition) {
setPosition(SpotifyStore.position); setPosition(SpotifyStore.position);
@ -359,7 +359,7 @@ export function Player() {
const [shouldHide, setShouldHide] = useState(false); const [shouldHide, setShouldHide] = useState(false);
// Hide player after 5 minutes of inactivity // Hide player after 5 minutes of inactivity
// eslint-disable-next-line consistent-return
useEffect(() => { useEffect(() => {
setShouldHide(false); setShouldHide(false);
if (!isPlaying) { if (!isPlaying) {

View file

@ -47,10 +47,10 @@ export interface Track {
interface PlayerState { interface PlayerState {
accountId: string; accountId: string;
track: Track | null; track: Track | null;
volumePercent?: number, volumePercent?: number;
isPlaying?: boolean, isPlaying?: boolean;
repeat: boolean, repeat: boolean;
position?: number, position?: number;
context?: any; context?: any;
device?: Device; device?: Device;

View file

@ -38,7 +38,7 @@ const Dismiss = ({ onDismiss }: { onDismiss: () => void; }) => (
</button> </button>
); );
export function TranslationAccessory({ message }: { message: MessageRecord & { vencordEmbeddedBy?: string[] }; }) { export function TranslationAccessory({ message }: { message: MessageRecord & { vencordEmbeddedBy?: string[]; }; }) {
const [translation, setTranslation] = useState<TranslationValue>(); const [translation, setTranslation] = useState<TranslationValue>();
useEffect(() => { useEffect(() => {

View file

@ -42,7 +42,7 @@ const settings = definePluginSettings({
} }
}); });
export const buildSeveralUsers = ({ a, b, count }: { a: string, b: string, count: number; }) => [ export const buildSeveralUsers = ({ a, b, count }: { a: string; b: string; count: number; }) => [
<strong key="0">{a}</strong>, <strong key="0">{a}</strong>,
", ", ", ",
<strong key="1">{b}</strong>, <strong key="1">{b}</strong>,

View file

@ -1,4 +1,4 @@
.vc-uvs-button>div { .vc-uvs-button > div {
white-space: normal !important; white-space: normal !important;
} }
@ -21,7 +21,7 @@
margin-bottom: 0 !important; margin-bottom: 0 !important;
} }
.vc-uvs-popout-margin-self>[class^="section"] { .vc-uvs-popout-margin-self > [class^="section"] {
padding-top: 0; padding-top: 0;
padding-bottom: 12px; padding-bottom: 12px;
} }

View file

@ -18,7 +18,7 @@ const enum ReferencedMessageState {
} }
interface Reply { interface Reply {
baseAuthor: UserRecord, baseAuthor: UserRecord;
baseMessage: MessageRecord; baseMessage: MessageRecord;
channel: ChannelRecord; channel: ChannelRecord;
referencedMessage: { state: ReferencedMessageState; }; referencedMessage: { state: ReferencedMessageState; };

View file

@ -146,7 +146,7 @@ function updateStatuses(type: string, { deaf, mute, selfDeaf, selfMute, userId,
*/ */
function playSample(tempSettings: any, type: string) { function playSample(tempSettings: any, type: string) {
const settings = Object.assign({}, Settings.plugins.VcNarrator, tempSettings); const settings = { ...Settings.plugins.VcNarrator, ...tempSettings };
const me = UserStore.getCurrentUser()!; const me = UserStore.getCurrentUser()!;
const currGuildId = SelectedGuildStore.getGuildId(); const currGuildId = SelectedGuildStore.getGuildId();

View file

@ -1,16 +1,16 @@
.vc-toolbox-btn, .vc-toolbox-btn,
.vc-toolbox-btn>svg { .vc-toolbox-btn > svg {
-webkit-app-region: no-drag; -webkit-app-region: no-drag;
} }
.vc-toolbox-btn>svg { .vc-toolbox-btn > svg {
color: var(--interactive-normal); color: var(--interactive-normal);
} }
.vc-toolbox-btn[class*="selected"]>svg { .vc-toolbox-btn[class*="selected"] > svg {
color: var(--interactive-active); color: var(--interactive-active);
} }
.vc-toolbox-btn:hover>svg { .vc-toolbox-btn:hover > svg {
color: var(--interactive-hover); color: var(--interactive-hover);
} }

View file

@ -135,7 +135,7 @@ function MakeContextCallback(name: "Guild" | "User" | "Channel"): NavContextMenu
if (!Array.isArray(p.children)) if (!Array.isArray(p.children))
p.children = [p.children]; p.children = [p.children];
children = p.children; ({ children } = p);
} }
children.splice(-1, 0, children.splice(-1, 0,

View file

@ -81,8 +81,8 @@ export default definePlugin({
}); });
type AudioMetadata = { type AudioMetadata = {
waveform: string, waveform: string;
duration: number, duration: number;
}; };
const EMPTY_META: AudioMetadata = { const EMPTY_META: AudioMetadata = {

View file

@ -287,7 +287,7 @@ export default definePlugin({
}, },
async paste() { async paste() {
const clip = (await navigator.clipboard.read())[0]; const [clip] = await navigator.clipboard.read();
if (!clip) return; if (!clip) return;
const data = new DataTransfer(); const data = new DataTransfer();

View file

@ -9,11 +9,11 @@ import type { LiteralUnion } from "type-fest";
// Resolves a possibly nested prop in the form of "some.nested.prop" to type of T.some.nested.prop // Resolves a possibly nested prop in the form of "some.nested.prop" to type of T.some.nested.prop
type ResolvePropDeep<T, P> = P extends `${infer Pre}.${infer Suf}` type ResolvePropDeep<T, P> = P extends `${infer Pre}.${infer Suf}`
? Pre extends keyof T ? Pre extends keyof T
? ResolvePropDeep<T[Pre], Suf> ? ResolvePropDeep<T[Pre], Suf>
: any : any
: P extends keyof T : P extends keyof T
? T[P] ? T[P]
: any; : any;
interface SettingsStoreOptions { interface SettingsStoreOptions {
readOnly?: boolean; readOnly?: boolean;
@ -26,6 +26,7 @@ interface SettingsStoreOptions {
} }
// merges the SettingsStoreOptions type into the class // merges the SettingsStoreOptions type into the class
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
export interface SettingsStore<T extends object> extends SettingsStoreOptions { } export interface SettingsStore<T extends object> extends SettingsStoreOptions { }
/** /**

View file

@ -32,5 +32,5 @@ document.addEventListener("DOMContentLoaded", () => {
document.head.append(Object.assign(document.createElement("style"), { document.head.append(Object.assign(document.createElement("style"), {
textContent: styleStr, textContent: styleStr,
id: "vencord-margins" id: "vencord-margins"
})), { once: true }; }));
}); }, { once: true });

View file

@ -82,11 +82,11 @@ interface AwaiterOpts<T> {
export function useAwaiter<T>(factory: () => Promise<T>): AwaiterRes<T | null>; export function useAwaiter<T>(factory: () => Promise<T>): AwaiterRes<T | null>;
export function useAwaiter<T>(factory: () => Promise<T>, providedOpts: AwaiterOpts<T>): AwaiterRes<T>; export function useAwaiter<T>(factory: () => Promise<T>, providedOpts: AwaiterOpts<T>): AwaiterRes<T>;
export function useAwaiter<T>(factory: () => Promise<T>, providedOpts?: AwaiterOpts<T | null>): AwaiterRes<T | null> { export function useAwaiter<T>(factory: () => Promise<T>, providedOpts?: AwaiterOpts<T | null>): AwaiterRes<T | null> {
const opts: AwaiterOpts<T | null> = Object.assign({ const opts: AwaiterOpts<T | null> = {
fallbackValue: null, fallbackValue: null,
deps: [], deps: [],
onError: null, ...providedOpts
}, providedOpts); };
const [state, setState] = useState({ const [state, setState] = useState({
value: opts.fallbackValue, value: opts.fallbackValue,
error: null, error: null,
@ -109,7 +109,7 @@ export function useAwaiter<T>(factory: () => Promise<T>, providedOpts?: AwaiterO
opts.onError?.(error); opts.onError?.(error);
}); });
return () => { (isAlive = false); }; return () => { isAlive = false; };
}, opts.deps); }, opts.deps);
return [state.value, state.error, state.pending]; return [state.value, state.error, state.pending];

View file

@ -81,7 +81,7 @@ export interface PluginDef {
* These will automatically be enabled and loaded before your plugin * These will automatically be enabled and loaded before your plugin
* Common examples are CommandsAPI, MessageEventsAPI... * Common examples are CommandsAPI, MessageEventsAPI...
*/ */
dependencies?: string[], dependencies?: string[];
/** /**
* Whether this plugin is required and forcefully enabled * Whether this plugin is required and forcefully enabled
*/ */
@ -98,7 +98,7 @@ export interface PluginDef {
* When to call the start() method * When to call the start() method
* @default StartAt.WebpackReady * @default StartAt.WebpackReady
*/ */
startAt?: StartAt, startAt?: StartAt;
/** /**
* Which parts of the plugin can be tested by the reporter. Defaults to all parts * Which parts of the plugin can be tested by the reporter. Defaults to all parts
*/ */
@ -170,8 +170,9 @@ export const enum OptionType {
export type SettingsDefinition = Record<string, PluginSettingDef>; export type SettingsDefinition = Record<string, PluginSettingDef>;
export type SettingsChecks<D extends SettingsDefinition> = { export type SettingsChecks<D extends SettingsDefinition> = {
[K in keyof D]?: D[K] extends PluginSettingComponentDef ? IsDisabled<DefinedSettings<D>> : [K in keyof D]?: D[K] extends PluginSettingComponentDef
(IsDisabled<DefinedSettings<D>> & IsValid<PluginSettingType<D[K]>, DefinedSettings<D>>); ? IsDisabled<DefinedSettings<D>>
: (IsDisabled<DefinedSettings<D>> & IsValid<PluginSettingType<D[K]>, DefinedSettings<D>>);
}; };
export type PluginSettingDef = ( export type PluginSettingDef = (
@ -328,7 +329,7 @@ export interface DefinedSettings<
export type PartialExcept<T, R extends keyof T> = Partial<T> & Required<Pick<T, R>>; export type PartialExcept<T, R extends keyof T> = Partial<T> & Required<Pick<T, R>>;
export type IpcRes<V = any> = { ok: true; value: V; } | { ok: false, error: any; }; export type IpcRes<V = any> = { ok: true; value: V; } | { ok: false; error: any; };
/* -------------------------------------------- */ /* -------------------------------------------- */
/* Legacy Options Types */ /* Legacy Options Types */
@ -352,6 +353,8 @@ export type PluginOptionComponent = PluginSettingComponentDef & PluginSettingCom
export type PluginNative<PluginExports extends Record<string, (event: Electron.IpcMainInvokeEvent, ...args: any[]) => any>> = { export type PluginNative<PluginExports extends Record<string, (event: Electron.IpcMainInvokeEvent, ...args: any[]) => any>> = {
[key in keyof PluginExports]: [key in keyof PluginExports]:
PluginExports[key] extends (event: Electron.IpcMainInvokeEvent, ...args: infer Args) => infer Return PluginExports[key] extends (event: Electron.IpcMainInvokeEvent, ...args: infer Args) => infer Return
? (...args: Args) => Return extends Promise<any> ? Return : Promise<Return> ? (...args: Args) => Return extends Promise<any>
: never; ? Return
: Promise<Return>
: never;
}; };

View file

@ -23,10 +23,10 @@ import type * as t from "./types/components";
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
export let Forms = {} as { export let Forms = {} as {
FormTitle: t.FormTitle, FormTitle: t.FormTitle;
FormSection: t.FormSection, FormSection: t.FormSection;
FormDivider: t.FormDivider, FormDivider: t.FormDivider;
FormText: t.FormText, FormText: t.FormText;
}; };
export let Card: t.Card; export let Card: t.Card;

View file

@ -23,7 +23,7 @@ import type * as t from "./types/menu";
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
export let Menu = {} as t.Menu; export let Menu = {} as t.Menu;
waitFor(["MenuItem", "MenuSliderControl"], m => Menu = m); waitFor(["MenuItem", "MenuSliderControl"], m => { Menu = m; });
export const ContextMenuApi: t.ContextMenuApi = mapMangledModuleLazy('type:"CONTEXT_MENU_OPEN', { export const ContextMenuApi: t.ContextMenuApi = mapMangledModuleLazy('type:"CONTEXT_MENU_OPEN', {
closeContextMenu: filters.byCode("CONTEXT_MENU_CLOSE"), closeContextMenu: filters.byCode("CONTEXT_MENU_CLOSE"),

View file

@ -55,49 +55,49 @@ export const useStateFromStoresObject: Stores.UseStateFromStoresObjectHook = pro
}); });
export let ChannelStore: Stores.ChannelStore; export let ChannelStore: Stores.ChannelStore;
waitForStore("ChannelStore", m => ChannelStore = m); waitForStore("ChannelStore", m => { ChannelStore = m; });
export let DraftStore: Stores.DraftStore; export let DraftStore: Stores.DraftStore;
waitForStore("DraftStore", s => DraftStore = s); waitForStore("DraftStore", s => { DraftStore = s; });
export let EmojiStore: Stores.EmojiStore; export let EmojiStore: Stores.EmojiStore;
waitForStore("EmojiStore", m => EmojiStore = m); waitForStore("EmojiStore", m => { EmojiStore = m; });
export let GuildChannelStore: Stores.GuildChannelStore; export let GuildChannelStore: Stores.GuildChannelStore;
waitForStore("GuildChannelStore", m => GuildChannelStore = m); waitForStore("GuildChannelStore", m => { GuildChannelStore = m; });
export let GuildMemberStore: Stores.GuildMemberStore; export let GuildMemberStore: Stores.GuildMemberStore;
waitForStore("GuildMemberStore", m => GuildMemberStore = m); waitForStore("GuildMemberStore", m => { GuildMemberStore = m; });
export let GuildStore: Stores.GuildStore; export let GuildStore: Stores.GuildStore;
waitForStore("GuildStore", m => GuildStore = m); waitForStore("GuildStore", m => { GuildStore = m; });
export let MessageStore: Stores.MessageStore; export let MessageStore: Stores.MessageStore;
waitForStore("MessageStore", m => MessageStore = m); waitForStore("MessageStore", m => { MessageStore = m; });
export let PermissionStore: Stores.PermissionStore; export let PermissionStore: Stores.PermissionStore;
waitForStore("PermissionStore", m => PermissionStore = m); waitForStore("PermissionStore", m => { PermissionStore = m; });
export let PresenceStore: Stores.PresenceStore; export let PresenceStore: Stores.PresenceStore;
waitForStore("PresenceStore", m => PresenceStore = m); waitForStore("PresenceStore", m => { PresenceStore = m; });
export let ReadStateStore: Stores.ReadStateStore; export let ReadStateStore: Stores.ReadStateStore;
waitForStore("ReadStateStore", m => ReadStateStore = m); waitForStore("ReadStateStore", m => { ReadStateStore = m; });
export let RelationshipStore: Stores.RelationshipStore; export let RelationshipStore: Stores.RelationshipStore;
waitForStore("RelationshipStore", m => RelationshipStore = m); waitForStore("RelationshipStore", m => { RelationshipStore = m; });
export let SelectedChannelStore: Stores.SelectedChannelStore; export let SelectedChannelStore: Stores.SelectedChannelStore;
waitForStore("SelectedChannelStore", m => SelectedChannelStore = m); waitForStore("SelectedChannelStore", m => { SelectedChannelStore = m; });
export let SelectedGuildStore: Stores.SelectedGuildStore; export let SelectedGuildStore: Stores.SelectedGuildStore;
waitForStore("SelectedGuildStore", m => SelectedGuildStore = m); waitForStore("SelectedGuildStore", m => { SelectedGuildStore = m; });
export let UserProfileStore: Stores.UserProfileStore; export let UserProfileStore: Stores.UserProfileStore;
waitForStore("UserProfileStore", m => UserProfileStore = m); waitForStore("UserProfileStore", m => { UserProfileStore = m; });
export let UserStore: Stores.UserStore; export let UserStore: Stores.UserStore;
waitForStore("UserStore", s => UserStore = s); waitForStore("UserStore", m => { UserStore = m; });
export let WindowStore: Stores.WindowStore; export let WindowStore: Stores.WindowStore;
waitForStore("WindowStore", m => WindowStore = m); waitForStore("WindowStore", m => { WindowStore = m; });

View file

@ -17,8 +17,8 @@
*/ */
export interface ImageModalClasses { export interface ImageModalClasses {
image: string, image: string;
modal: string, modal: string;
} }
export interface ButtonWrapperClasses { export interface ButtonWrapperClasses {

View file

@ -419,7 +419,7 @@ export type Popout = ComponentType<{
export type Dialog = ComponentType<JSX.IntrinsicElements["div"]>; export type Dialog = ComponentType<JSX.IntrinsicElements["div"]>;
type Resolve = (data: { theme: "light" | "dark", saturation: number; }) => { type Resolve = (data: { theme: "light" | "dark"; saturation: number; }) => {
hex(): string; hex(): string;
hsl(): string; hsl(): string;
int(): number; int(): number;
@ -445,7 +445,7 @@ export type MaskedLink = ComponentType<PropsWithChildren<{
href: string; href: string;
rel?: string; rel?: string;
target?: string; target?: string;
title?: string, title?: string;
className?: string; className?: string;
tabIndex?: number; tabIndex?: number;
onClick?(): void; onClick?(): void;

View file

@ -66,11 +66,11 @@ export interface Menu {
interactive?: boolean; interactive?: boolean;
}>; }>;
MenuSliderControl: RC<{ MenuSliderControl: RC<{
minValue: number, minValue: number;
maxValue: number, maxValue: number;
value: number, value: number;
onChange(value: number): void, onChange(value: number): void;
renderValue?(value: number): string, renderValue?(value: number): string;
}>; }>;
} }

View file

@ -92,18 +92,18 @@ export interface RouterUtils {
export interface IconUtils { export interface IconUtils {
getUserAvatarURL(user: UserRecord, canAnimate?: boolean, size?: number, format?: string): string; getUserAvatarURL(user: UserRecord, canAnimate?: boolean, size?: number, format?: string): string;
getDefaultAvatarURL(id: string, discriminator?: string): string; getDefaultAvatarURL(id: string, discriminator?: string): string;
getUserBannerURL(data: { id: string, banner: string, canAnimate?: boolean, size: number; }): string | undefined; getUserBannerURL(data: { id: string; banner: string; canAnimate?: boolean; size: number; }): string | undefined;
getAvatarDecorationURL(data: { avatarDecoration: string, size: number; canCanimate?: boolean; }): string | undefined; getAvatarDecorationURL(data: { avatarDecoration: string; size: number; canCanimate?: boolean; }): string | undefined;
getGuildMemberAvatarURL(member: GuildMember, canAnimate?: string): string | null; getGuildMemberAvatarURL(member: GuildMember, canAnimate?: string): string | null;
getGuildMemberAvatarURLSimple(data: { guildId: string, userId: string, avatar: string, canAnimate?: boolean; size?: number; }): string; getGuildMemberAvatarURLSimple(data: { guildId: string; userId: string; avatar: string; canAnimate?: boolean; size?: number; }): string;
getGuildMemberBannerURL(data: { id: string, guildId: string, banner: string, canAnimate?: boolean, size: number; }): string | undefined; getGuildMemberBannerURL(data: { id: string; guildId: string; banner: string; canAnimate?: boolean; size: number; }): string | undefined;
getGuildIconURL(data: { id: string, icon?: string, size?: number, canAnimate?: boolean; }): string | undefined; getGuildIconURL(data: { id: string; icon?: string; size?: number; canAnimate?: boolean; }): string | undefined;
getGuildBannerURL(guild: GuildRecord, canAnimate?: boolean): string | null; getGuildBannerURL(guild: GuildRecord, canAnimate?: boolean): string | null;
getChannelIconURL(data: { id: string; icon?: string | null | undefined; applicationId?: string; size?: number; }): string | undefined; getChannelIconURL(data: { id: string; icon?: string | null | undefined; applicationId?: string; size?: number; }): string | undefined;
getEmojiURL(data: { id: string, animated: boolean, size: number, forcePNG?: boolean; }): string; getEmojiURL(data: { id: string; animated: boolean; size: number; forcePNG?: boolean; }): string;
hasAnimatedGuildIcon(guild: GuildRecord): boolean; hasAnimatedGuildIcon(guild: GuildRecord): boolean;
isAnimatedIconHash(hash: string): boolean; isAnimatedIconHash(hash: string): boolean;

View file

@ -53,12 +53,12 @@ const ToastPosition = {
}; };
export interface ToastData { export interface ToastData {
message: string, message: string;
id: string, id: string;
/** /**
* Toasts.Type * Toasts.Type
*/ */
type: number, type: number;
options?: ToastOptions; options?: ToastOptions;
} }
@ -67,7 +67,7 @@ export interface ToastOptions {
* Toasts.Position * Toasts.Position
*/ */
position?: number; position?: number;
component?: ReactNode, component?: ReactNode;
duration?: number; duration?: number;
} }
@ -102,7 +102,7 @@ export function showToast(message: string, type = ToastType.MESSAGE, options?: T
} }
export let AlertActionCreators: t.AlertActionCreators; export let AlertActionCreators: t.AlertActionCreators;
waitFor(["show", "close"], m => AlertActionCreators = m); waitFor(["show", "close"], m => { AlertActionCreators = m; });
export const ApplicationAssetUtils: { export const ApplicationAssetUtils: {
fetchAssetIds: (applicationId: string, e: string[]) => Promise<string[]>; fetchAssetIds: (applicationId: string, e: string[]) => Promise<string[]>;
@ -118,7 +118,7 @@ export const ClipboardUtils: t.ClipboardUtils = mapMangledModuleLazy('queryComma
}); });
export let ComponentDispatch: any; export let ComponentDispatch: any;
waitFor(["ComponentDispatch", "ComponentDispatcher"], m => ComponentDispatch = m.ComponentDispatch); waitFor(["ComponentDispatch", "ComponentDispatcher"], m => { ({ ComponentDispatch } = m); });
export const Constants = findByPropsLazy("Endpoints"); export const Constants = findByPropsLazy("Endpoints");
@ -149,7 +149,7 @@ export const InstantInviteActionCreators = findByPropsLazy("resolveInvite");
export const lodash: typeof import("lodash") = findByPropsLazy("debounce", "cloneDeep"); export const lodash: typeof import("lodash") = findByPropsLazy("debounce", "cloneDeep");
export let MarkupUtils: t.MarkupUtils; export let MarkupUtils: t.MarkupUtils;
waitFor("parseTopic", m => MarkupUtils = m); waitFor("parseTopic", m => { MarkupUtils = m; });
export const MessageActionCreators = findByPropsLazy("editMessage", "sendMessage"); export const MessageActionCreators = findByPropsLazy("editMessage", "sendMessage");
@ -176,7 +176,7 @@ export const RouterUtils: t.RouterUtils = mapMangledModuleLazy("Transitioning to
}); });
export let SnowflakeUtils: t.SnowflakeUtils; export let SnowflakeUtils: t.SnowflakeUtils;
waitFor(["fromTimestamp", "extractTimestamp"], m => SnowflakeUtils = m); waitFor(["fromTimestamp", "extractTimestamp"], m => { SnowflakeUtils = m; });
export const UploadAttachmentActionCreators = findByPropsLazy("clearAll", "addFile"); export const UploadAttachmentActionCreators = findByPropsLazy("clearAll", "addFile");
@ -187,7 +187,7 @@ export const UserActionCreators = {
export const UserProfileModalActionCreators = findByPropsLazy("openUserProfileModal", "closeUserProfileModal"); export const UserProfileModalActionCreators = findByPropsLazy("openUserProfileModal", "closeUserProfileModal");
export let UserSettingsModalActionCreators: any; export let UserSettingsModalActionCreators: any;
waitFor(["open", "saveAccountChanges"], m => UserSettingsModalActionCreators = m); waitFor(["open", "saveAccountChanges"], m => { UserSettingsModalActionCreators = m; });
export const UserUtils: t.UserUtils = findByPropsLazy("useName", "getGlobalName"); export const UserUtils: t.UserUtils = findByPropsLazy("useName", "getGlobalName");

View file

@ -180,7 +180,7 @@ function patchFactories(factories: Record<string, (module: any, exports: any, re
return; return;
} }
exports = module.exports; ({ exports } = module);
if (!exports) return; if (!exports) return;
@ -245,7 +245,7 @@ function patchFactories(factories: Record<string, (module: any, exports: any, re
logger.error("Error while firing callback for Webpack subscription:\n", err, filter, callback); logger.error("Error while firing callback for Webpack subscription:\n", err, filter, callback);
} }
} }
} as any as { toString: () => string, original: any, (...args: any[]): void; }; } as any as { toString: () => string; original: any; (...args: any[]): void; };
factory.toString = originalMod.toString.bind(originalMod); factory.toString = originalMod.toString.bind(originalMod);
factory.original = originalMod; factory.original = originalMod;

View file

@ -603,7 +603,7 @@ export function waitFor(filter: string | PropsFilter | FilterFn, callback: Callb
else if (typeof filter !== "function") else if (typeof filter !== "function")
throw new Error("filter must be a string, string[] or function, got " + typeof filter); throw new Error("filter must be a string, string[] or function, got " + typeof filter);
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (cache != null) { if (cache != null) {
const [existing, id] = find(filter, { isIndirect: true, isWaitFor: true }); const [existing, id] = find(filter, { isIndirect: true, isWaitFor: true });
if (existing) { if (existing) {