From ba267f8fcd2a1b130643c53d5652eb5d15376166 Mon Sep 17 00:00:00 2001 From: Sorunome <mail@sorunome.de> Date: Mon, 29 Oct 2018 20:53:05 +0100 Subject: [PATCH] strictNullChecks on main code --- src/bot.ts | 35 +++++++++++++++++++---------------- src/channelsyncroniser.ts | 30 +++++++++++++++--------------- src/clientfactory.ts | 6 +++--- src/config.ts | 4 ++-- src/db/dbdataevent.ts | 4 ++-- src/db/schema/v3.ts | 2 +- src/log.ts | 2 +- src/matrixeventprocessor.ts | 32 ++++++++++++++++++++------------ src/matrixroomhandler.ts | 6 +++--- src/messageprocessor.ts | 6 +++--- src/presencehandler.ts | 2 +- src/provisioner.ts | 2 +- src/store.ts | 2 +- src/usersyncroniser.ts | 31 +++++++++++++++++-------------- src/util.ts | 24 ++++++++++++------------ tsconfig.json | 3 ++- 16 files changed, 103 insertions(+), 88 deletions(-) diff --git a/src/bot.ts b/src/bot.ts index d005e91..ccf0772 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -185,15 +185,15 @@ export class DiscordBot { } if (this.bot.guilds.has(guildId) ) { const guild = this.bot.guilds.get(guildId); - return guild.channels.filter((channel) => { + return guild!.channels.filter((channel) => { return channel.name.toLowerCase() === channelName.toLowerCase(); // Implement searching in the future. }).map((channel) => { return { - alias: `#_discord_${guild.id}_${channel.id}:${this.config.bridge.domain}`, + alias: `#_discord_${guild!.id}_${channel.id}:${this.config.bridge.domain}`, fields: { channel_id: channel.id, channel_name: channel.name, - guild_id: guild.id, + guild_id: guild!.id, }, protocol: "discord", } as IThirdPartyLookup; @@ -205,7 +205,7 @@ export class DiscordBot { } public async LookupRoom(server: string, room: string, sender?: string): Promise<ChannelLookupResult> { - const hasSender = sender !== null; + const hasSender = sender !== null && sender !== undefined; try { const client = await this.clientFactory.getClient(sender); const guild = client.guilds.get(server); @@ -224,7 +224,7 @@ export class DiscordBot { log.verbose("LookupRoom => ", err); if (hasSender) { log.verbose(`Couldn't find guild/channel under user account. Falling back.`); - return await this.LookupRoom(server, room, null); + return await this.LookupRoom(server, room); } throw err; } @@ -253,7 +253,7 @@ export class DiscordBot { }); } - public async ProcessMatrixMsgEvent(event: IMatrixEvent, guildId: string, channelId: string): Promise<null> { + public async ProcessMatrixMsgEvent(event: IMatrixEvent, guildId: string, channelId: string): Promise<void> { const mxClient = this.bridge.getClientFactory().getClientAs(); log.verbose(`Looking up ${guildId}_${channelId}`); const result = await this.LookupRoom(guildId, channelId, event.sender); @@ -277,8 +277,8 @@ export class DiscordBot { opts.file = file; } - let msg = null; - let hook: Discord.Webhook ; + let msg: Discord.Message | null | (Discord.Message | null)[] = null; + let hook: Discord.Webhook | undefined; if (botUser) { const webhooks = await chan.fetchWebhooks(); hook = webhooks.filterArray((h) => h.name === "_matrix").pop(); @@ -300,14 +300,14 @@ export class DiscordBot { msg = await chan.send(embed.description, opts); } else if (hook) { msg = await hook.send(embed.description, { - avatarURL: embed.author.icon_url, + avatarURL: embed!.author!.icon_url, embeds: embedSet.replyEmbed ? [embedSet.replyEmbed] : undefined, files: opts.file ? [opts.file] : undefined, - username: embed.author.name, + username: embed!.author!.name, } as Discord.WebhookMessageOptions); } else { if (embedSet.replyEmbed) { - embed.addField("Replying to", embedSet.replyEmbed.author.name); + embed.addField("Replying to", embedSet.replyEmbed!.author!.name); embed.addField("Reply text", embedSet.replyEmbed.description); } opts.embed = embed; @@ -342,7 +342,7 @@ export class DiscordBot { const storeEvent = await this.store.Get(DbEvent, {matrix_id: event.redacts + ";" + event.room_id}); - if (!storeEvent.Result) { + if (!storeEvent || !storeEvent.Result) { log.warn(`Could not redact because the event was not in the store.`); return; } @@ -368,10 +368,10 @@ export class DiscordBot { public async GetDiscordUserOrMember( userId: Discord.Snowflake, guildId?: Discord.Snowflake, - ): Promise<Discord.User|Discord.GuildMember> { + ): Promise<Discord.User|Discord.GuildMember|undefined> { try { if (guildId && this.bot.guilds.has(guildId)) { - return await this.bot.guilds.get(guildId).fetchMember(userId); + return await this.bot.guilds.get(guildId)!.fetchMember(userId); } return await this.bot.fetchUser(userId); } catch (ex) { @@ -405,7 +405,10 @@ export class DiscordBot { if (!id.match(/^\d+$/)) { throw new Error("Non-numerical ID"); } - const dbEmoji: DbEmoji = await this.store.Get(DbEmoji, {emoji_id: id}); + const dbEmoji = await this.store.Get(DbEmoji, {emoji_id: id}); + if (!dbEmoji) { + throw new Error("Couldn't fetch from store"); + } if (!dbEmoji.Result) { const url = "https://cdn.discordapp.com/emojis/" + id + (animated ? ".gif" : ".png"); const intent = this.bridge.getIntent(); @@ -620,7 +623,7 @@ export class DiscordBot { private async DeleteDiscordMessage(msg: Discord.Message) { log.info(`Got delete event for ${msg.id}`); const storeEvent = await this.store.Get(DbEvent, {discord_id: msg.id}); - if (!storeEvent.Result) { + if (!storeEvent || !storeEvent.Result) { log.warn(`Could not redact because the event was not in the store.`); return; } diff --git a/src/channelsyncroniser.ts b/src/channelsyncroniser.ts index 8cecd2e..997b72b 100644 --- a/src/channelsyncroniser.ts +++ b/src/channelsyncroniser.ts @@ -17,26 +17,26 @@ const DEFAULT_CHANNEL_STATE = { const DEFAULT_SINGLECHANNEL_STATE = { iconId: null, - iconUrl: null, // nullable + iconUrl: null, mxid: null, - name: null, // nullable + name: null, removeIcon: false, - topic: null, // nullable + topic: null, }; export interface ISingleChannelState { mxid: string; - name: string; // nullable - topic: string; // nullable - iconUrl: string; // nullable - iconId: string; // nullable + name: string | null; + topic: string | null; + iconUrl: string | null; + iconId: string | null; removeIcon: boolean; } export interface IChannelState { id: string; mxChannels: ISingleChannelState[]; - iconMxcUrl: string; // nullable + iconMxcUrl: string | null; } export class ChannelSyncroniser { @@ -63,7 +63,7 @@ export class ChannelSyncroniser { public async OnGuildUpdate(guild: Discord.Guild, force = false) { log.verbose(`Got guild update for guild ${guild.id}`); - const channelStates = []; + const channelStates: IChannelState[] = []; for (const [_, channel] of guild.channels) { if (channel.type !== "text") { continue; // not supported for now @@ -76,7 +76,7 @@ export class ChannelSyncroniser { } } - let iconMxcUrl = null; + let iconMxcUrl: string | null = null; for (const channelState of channelStates) { channelState.iconMxcUrl = channelState.iconMxcUrl || iconMxcUrl; try { @@ -135,7 +135,7 @@ export class ChannelSyncroniser { public async GetChannelUpdateState(channel: Discord.TextChannel, forceUpdate = false): Promise<IChannelState> { log.verbose(`State update request for ${channel.id}`); - const channelState = Object.assign({}, DEFAULT_CHANNEL_STATE, { + const channelState: IChannelState = Object.assign({}, DEFAULT_CHANNEL_STATE, { id: channel.id, mxChannels: [], }); @@ -150,19 +150,19 @@ export class ChannelSyncroniser { guild: channel.guild.name, name: "#" + channel.name, }; - let name = this.config.channel.namePattern; + let name: string = this.config.channel.namePattern; for (const p of Object.keys(patternMap)) { name = name.replace(new RegExp(":" + p, "g"), patternMap[p]); } const topic = channel.topic; const icon = channel.guild.icon; - let iconUrl = null; + let iconUrl: string | null = null; if (icon) { iconUrl = `https://cdn.discordapp.com/icons/${channel.guild.id}/${icon}.png`; } remoteRooms.forEach((remoteRoom) => { const mxid = remoteRoom.matrix.getId(); - const singleChannelState = Object.assign({}, DEFAULT_SINGLECHANNEL_STATE, { + const singleChannelState: ISingleChannelState = Object.assign({}, DEFAULT_SINGLECHANNEL_STATE, { mxid, }); @@ -219,7 +219,7 @@ export class ChannelSyncroniser { roomUpdated = true; } - if (channelState.iconUrl !== null) { + if (channelState.iconUrl !== null && channelState.iconId !== null) { log.verbose(`Updating icon_url for ${channelState.mxid} to "${channelState.iconUrl}"`); if (channelsState.iconMxcUrl === null) { const iconMxc = await Util.UploadContentFromUrl( diff --git a/src/clientfactory.ts b/src/clientfactory.ts index adb3bb8..3f5b947 100644 --- a/src/clientfactory.ts +++ b/src/clientfactory.ts @@ -15,7 +15,7 @@ export class DiscordClientFactory { private botClient: Matrix.Client; private clients: Map<string, Matrix.Client>; constructor(store: DiscordStore, config?: DiscordBridgeConfigAuth) { - this.config = config; + this.config = config!; this.clients = new Map(); this.store = store; } @@ -59,8 +59,8 @@ export class DiscordClientFactory { }); } - public async getClient(userId: string = null): Promise<Matrix.Client> { - if (userId == null) { + public async getClient(userId: string | null = null): Promise<Matrix.Client> { + if (userId === null) { return this.botClient; } if (this.clients.has(userId)) { diff --git a/src/config.ts b/src/config.ts index 031a7ee..c5dfb88 100644 --- a/src/config.ts +++ b/src/config.ts @@ -67,8 +67,8 @@ class DiscordBridgeConfigChannel { } class DiscordBridgeConfigChannelDeleteOptions { - public namePrefix: string = null; - public topicPrefix: string = null; + public namePrefix: string | null = null; + public topicPrefix: string | null = null; public disableMessaging: boolean = false; public unsetRoomAlias: boolean = true; public unlistFromDirectory: boolean = true; diff --git a/src/db/dbdataevent.ts b/src/db/dbdataevent.ts index 29fd9ec..496a428 100644 --- a/src/db/dbdataevent.ts +++ b/src/db/dbdataevent.ts @@ -17,7 +17,8 @@ export class DbEvent implements IDbDataMany { // tslint:disable-next-line no-any public async RunQuery(store: DiscordStore, params: any): Promise<void> { this.rows = []; - let rowsM = null; + // tslint:disable-next-line no-any + let rowsM: any[] | null = null; if (params.matrix_id) { rowsM = await store.db.All(` SELECT * @@ -55,7 +56,6 @@ export class DbEvent implements IDbDataMany { } } this.Result = this.rows.length !== 0; - return null; } public Next(): boolean { diff --git a/src/db/schema/v3.ts b/src/db/schema/v3.ts index 952e046..60cf3e7 100644 --- a/src/db/schema/v3.ts +++ b/src/db/schema/v3.ts @@ -42,7 +42,7 @@ export class Schema implements IDbSchema { )]); } - private async moveUserIds(store: DiscordStore): Promise <null> { + private async moveUserIds(store: DiscordStore): Promise <void> { log.info("Performing one time moving of tokens to new table. Please wait."); let rows; try { diff --git a/src/log.ts b/src/log.ts index 8a895de..96905f9 100644 --- a/src/log.ts +++ b/src/log.ts @@ -29,7 +29,7 @@ export class Log { } private static config: DiscordBridgeConfigLogging; - private static logger: Logger = null; + private static logger: Logger; private static now() { return moment().format(Log.config.lineDateFormat); diff --git a/src/matrixeventprocessor.ts b/src/matrixeventprocessor.ts index 8991490..7cbe8d0 100644 --- a/src/matrixeventprocessor.ts +++ b/src/matrixeventprocessor.ts @@ -45,7 +45,7 @@ export class MatrixEventProcessor { this.discord = opts.discord; } - public StateEventToMessage(event: IMatrixEvent, channel: Discord.TextChannel): string { + public StateEventToMessage(event: IMatrixEvent, channel: Discord.TextChannel): string | undefined { const SUPPORTED_EVENTS = ["m.room.member", "m.room.name", "m.room.topic"]; if (!SUPPORTED_EVENTS.includes(event.type)) { log.verbose(`${event.event_id} ${event.type} is not displayable.`); @@ -60,11 +60,11 @@ export class MatrixEventProcessor { let msg = `\`${event.sender}\` `; if (event.type === "m.room.name") { - msg += `set the name to \`${event.content.name}\``; + msg += `set the name to \`${event.content!.name}\``; } else if (event.type === "m.room.topic") { - msg += `set the topic to \`${event.content.topic}\``; + msg += `set the topic to \`${event.content!.topic}\``; } else if (event.type === "m.room.member") { - const membership = event.content.membership; + const membership = event.content!.membership; if (membership === "join" && event.unsigned.prev_content === undefined) { msg += `joined the room`; @@ -86,9 +86,9 @@ export class MatrixEventProcessor { public async EventToEmbed( event: IMatrixEvent, profile: IMatrixEvent|null, channel: Discord.TextChannel, ): Promise<IMatrixEventProcessorResult> { - let body = this.config.bridge.disableDiscordMentions ? event.content.body : + let body: string = this.config.bridge.disableDiscordMentions ? event.content!.body as string : this.FindMentionsInPlainBody( - event.content.body, + event.content!.body as string, channel.members.array(), ); @@ -113,7 +113,7 @@ export class MatrixEventProcessor { }*/ // Replace /me with * username ... - if (event.content.msgtype === "m.emote") { + if (event.content!.msgtype === "m.emote") { if (profile && profile.displayname && profile.displayname.length >= MIN_NAME_LENGTH && @@ -172,26 +172,30 @@ export class MatrixEventProcessor { } public async HandleAttachment(event: IMatrixEvent, mxClient: Matrix.Client): Promise<string|Discord.FileOptions> { + if (!event.content) { + event.content = {}; + } + const hasAttachment = [ "m.image", "m.audio", "m.video", "m.file", "m.sticker", - ].includes(event.content.msgtype) || [ + ].includes(event.content.msgtype as string) || [ "m.sticker", ].includes(event.type); if (!hasAttachment) { return ""; } - if (event.content.info == null) { + if (!event.content.info) { // Fractal sends images without an info, which is technically allowed // but super unhelpful: https://gitlab.gnome.org/World/fractal/issues/206 event.content.info = {size: 0}; } - if (event.content.url == null) { + if (!event.content.url) { log.info("Event was an attachment type but was missing a content.url"); return ""; } @@ -213,6 +217,10 @@ export class MatrixEventProcessor { } public async GetEmbedForReply(event: IMatrixEvent): Promise<[Discord.RichEmbed, string]|undefined> { + if (!event.content) { + event.content = {}; + } + const relatesTo = event.content["m.relates_to"]; let eventId = null; if (relatesTo && relatesTo["m.in_reply_to"]) { @@ -250,7 +258,7 @@ export class MatrixEventProcessor { return [embed, reponseText]; } - private async SetEmbedAuthor(embed: Discord.RichEmbed, sender: string, profile?: IMatrixEvent) { + private async SetEmbedAuthor(embed: Discord.RichEmbed, sender: string, profile?: IMatrixEvent | null) { const intent = this.bridge.getIntent(); let displayName = sender; let avatarUrl; @@ -274,7 +282,7 @@ export class MatrixEventProcessor { } // Let it fall through. } - if (profile === undefined) { + if (!profile) { try { profile = await intent.getProfileInfo(sender); } catch (ex) { diff --git a/src/matrixroomhandler.ts b/src/matrixroomhandler.ts index 265cba1..7c107d3 100644 --- a/src/matrixroomhandler.ts +++ b/src/matrixroomhandler.ts @@ -81,7 +81,7 @@ export class MatrixRoomHandler { "public", ); await this.discord.ChannelSyncroniser.OnUpdate(channel); - const promiseList = []; + const promiseList: Promise<void>[] = []; /* We delay the joins to give some implementations a chance to breathe */ // Join a whole bunch of users. /* We delay the joins to give some implementations a chance to breathe */ @@ -228,7 +228,7 @@ export class MatrixRoomHandler { }); } - const {command, args} = Util.MsgToArgs(event.content.body, "!discord"); + const {command, args} = Util.MsgToArgs(event.content!.body as string, "!discord"); if (command === "help" && args[0] === "bridge") { const link = Util.GetBotLink(this.config); @@ -505,7 +505,7 @@ export class MatrixRoomHandler { private DiscordModerationActionGenerator(discordChannel: Discord.TextChannel, funcKey: string, action: string) { return async ({name}) => { - let allChannelMxids = []; + let allChannelMxids: string[] = []; await Promise.all(discordChannel.guild.channels.map(async (chan) => { try { const chanMxids = await this.discord.ChannelSyncroniser.GetRoomIdsFromChannel(chan); diff --git a/src/messageprocessor.ts b/src/messageprocessor.ts index 32beb2f..5f4967a 100644 --- a/src/messageprocessor.ts +++ b/src/messageprocessor.ts @@ -45,7 +45,7 @@ function _setupMarked() { } export class MessageProcessorOpts { - constructor(readonly domain: string, readonly bot: DiscordBot = null) { + constructor(readonly domain: string, readonly bot: DiscordBot) { } } @@ -57,9 +57,9 @@ export class MessageProcessorMatrixResult { export class MessageProcessor { private readonly opts: MessageProcessorOpts; - constructor(opts: MessageProcessorOpts, bot: DiscordBot = null) { + constructor(opts: MessageProcessorOpts, bot: DiscordBot | null = null) { // Backwards compat - if (bot != null) { + if (bot !== null) { this.opts = new MessageProcessorOpts(opts.domain, bot); } else { this.opts = opts; diff --git a/src/presencehandler.ts b/src/presencehandler.ts index 9c6d946..eb661c5 100644 --- a/src/presencehandler.ts +++ b/src/presencehandler.ts @@ -44,7 +44,7 @@ export class PresenceHandler { } log.info("Stopping presence handler"); clearInterval(this.interval); - this.interval = null; + this.interval = 0; } public EnqueueUser(user: User) { diff --git a/src/provisioner.ts b/src/provisioner.ts index 1a43db0..044e5a5 100644 --- a/src/provisioner.ts +++ b/src/provisioner.ts @@ -77,7 +77,7 @@ export class Provisioner { } const perms = channel.permissionsFor(member); - if (!perms.hasPermission(Discord.Permissions.FLAGS.MANAGE_WEBHOOKS)) { + if (!perms.hasPermission(Discord.Permissions.FLAGS.MANAGE_WEBHOOKS as Discord.PermissionResolvable)) { // Missing permissions, so just reject it throw new Error("You do not have permission to manage webhooks in this channel"); } diff --git a/src/store.ts b/src/store.ts index 0b0ef70..060750f 100644 --- a/src/store.ts +++ b/src/store.ts @@ -26,7 +26,7 @@ export class DiscordStore { } else { this.config = configOrFile; } - this.version = null; + this.version = 0; } public async backup_database(): Promise<void|{}> { diff --git a/src/usersyncroniser.ts b/src/usersyncroniser.ts index 89ff6ab..6bf6862 100644 --- a/src/usersyncroniser.ts +++ b/src/usersyncroniser.ts @@ -9,17 +9,17 @@ import { Log } from "./log"; const log = new Log("UserSync"); const DEFAULT_USER_STATE = { - avatarId: null, - avatarUrl: null, // Nullable + avatarId: "", + avatarUrl: null, createUser: false, - displayName: null, // Nullable + displayName: null, id: null, mxUserId: null, removeAvatar: false, }; const DEFAULT_GUILD_STATE = { - displayName: null, + displayName: "", id: null, mxUserId: null, roles: [], @@ -27,9 +27,9 @@ const DEFAULT_GUILD_STATE = { export interface IUserState { avatarId: string; - avatarUrl: string; // Nullable + avatarUrl: string | null; createUser: boolean; - displayName: string; // Nullable + displayName: string | null; id: string; mxUserId: string; removeAvatar: boolean; // If the avatar has been removed from the user. @@ -88,7 +88,7 @@ export class UserSyncroniser { public async ApplyStateToProfile(userState: IUserState) { const intent = this.bridge.getIntent(userState.mxUserId); let userUpdated = false; - let remoteUser = null; + let remoteUser: RemoteUser; if (userState.createUser) { /* NOTE: Setting the displayname/avatar will register the user if they don't exist */ log.info(`Creating new user ${userState.mxUserId}`); @@ -184,7 +184,7 @@ export class UserSyncroniser { public async GetUserUpdateState(discordUser: User): Promise<IUserState> { log.verbose(`State update requested for ${discordUser.id}`); - const userState = Object.assign({}, DEFAULT_USER_STATE, { + const userState: IUserState = Object.assign({}, DEFAULT_USER_STATE, { id: discordUser.id, mxUserId: `@_discord_${discordUser.id}:${this.config.bridge.domain}`, }); @@ -222,9 +222,12 @@ export class UserSyncroniser { public async GetUserStateForGuildMember( newMember: GuildMember, - displayname: string, + displayname?: string, ): Promise<IGuildMemberState> { - const guildState = Object.assign({}, DEFAULT_GUILD_STATE, { + if (!displayname) { + displayname = ""; + } + const guildState: IGuildMemberState = Object.assign({}, DEFAULT_GUILD_STATE, { id: newMember.id, mxUserId: `@_discord_${newMember.id}:${this.config.bridge.domain}`, roles: newMember.roles.map((role) => { return { @@ -284,7 +287,7 @@ export class UserSyncroniser { if (guild.members.has(id)) { log.info(`Updating user ${id} in guild ${guild.id}.`); const member = guild.members.get(id); - const state = await this.GetUserStateForGuildMember(member, remoteUser.get("displayname")); + const state = await this.GetUserStateForGuildMember(member!, remoteUser.get("displayname")); const rooms = await this.discord.GetRoomIdsFromGuild(guild.id); return Promise.all( rooms.map( @@ -324,7 +327,7 @@ export class UserSyncroniser { log.warn(`Got member update for ${roomId}, but no channel or guild member could be found.`); return UserSyncroniser.ERR_CHANNEL_MEMBER_NOT_FOUND; } - const state = await this.GetUserStateForGuildMember(member, ev.content.displayname); + const state = await this.GetUserStateForGuildMember(member, ev.content!.displayname); return this.ApplyStateToRoom(state, roomId, member.guild.id); } @@ -332,14 +335,14 @@ export class UserSyncroniser { const userStateKey = `${ev.room_id}${ev.state_key}`; if (this.userStateHold.has(userStateKey)) { const oldEv = this.userStateHold.get(userStateKey); - if (ev.origin_server_ts > oldEv.origin_server_ts) { + if (ev.origin_server_ts! > oldEv!.origin_server_ts!) { return false; // New event is older } } this.userStateHold.set(userStateKey, ev); // tslint:disable-next-line:await-promise await Bluebird.delay(delayMs); - if (this.userStateHold.get(userStateKey).event_id !== ev.event_id) { + if (this.userStateHold.get(userStateKey)!.event_id !== ev.event_id) { // Event has changed and we are out of date. return false; } diff --git a/src/util.ts b/src/util.ts index 09afd90..10ea21a 100644 --- a/src/util.ts +++ b/src/util.ts @@ -94,7 +94,7 @@ export class Util { * uploadContentFromUrl - Upload content from a given URL to the homeserver * and return a MXC URL. */ - public static async UploadContentFromUrl(url: string, intent: Intent, name: string): Promise<IUploadResult> { + public static async UploadContentFromUrl(url: string, intent: Intent, name: string | null): Promise<IUploadResult> { let contenttype; let size; name = name || null; @@ -164,16 +164,16 @@ export class Util { public static GetBotLink(config: DiscordBridgeConfig): string { /* tslint:disable:no-bitwise */ - const perms = Permissions.FLAGS.READ_MESSAGES | - Permissions.FLAGS.SEND_MESSAGES | - Permissions.FLAGS.CHANGE_NICKNAME | - Permissions.FLAGS.CONNECT | - Permissions.FLAGS.SPEAK | - Permissions.FLAGS.EMBED_LINKS | - Permissions.FLAGS.ATTACH_FILES | - Permissions.FLAGS.READ_MESSAGE_HISTORY | - Permissions.FLAGS.MANAGE_WEBHOOKS | - Permissions.FLAGS.MANAGE_MESSAGES; + const perms = Permissions.FLAGS.READ_MESSAGES! | + Permissions.FLAGS.SEND_MESSAGES! | + Permissions.FLAGS.CHANGE_NICKNAME! | + Permissions.FLAGS.CONNECT! | + Permissions.FLAGS.SPEAK! | + Permissions.FLAGS.EMBED_LINKS! | + Permissions.FLAGS.ATTACH_FILES! | + Permissions.FLAGS.READ_MESSAGE_HISTORY! | + Permissions.FLAGS.MANAGE_WEBHOOKS! | + Permissions.FLAGS.MANAGE_MESSAGES!; /* tslint:enable:no-bitwise */ const clientId = config.auth.clientID; @@ -254,7 +254,7 @@ export class Util { public static MsgToArgs(msg: string, prefix: string) { prefix += " "; let command = "help"; - let args = []; + let args: string[] = []; if (msg.length >= prefix.length) { const allArgs = msg.substring(prefix.length).split(" "); if (allArgs.length && allArgs[0] !== "") { diff --git a/tsconfig.json b/tsconfig.json index acfe5f9..5b8c855 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,7 +6,8 @@ "noImplicitAny": false, "sourceMap": false, "outDir": "./build", - "types": ["mocha", "node"] + "types": ["mocha", "node"], + "strictNullChecks": true }, "compileOnSave": true, "include": [ -- GitLab