refactor: prefer switches over ifs when possible

This commit is contained in:
teidesu 2021-05-16 14:32:36 +03:00
parent f9336841ab
commit e6e28399b0
28 changed files with 546 additions and 574 deletions

View file

@ -1,4 +1,4 @@
import { MtCuteError, User, TermsOfService } from '../../types' import { User, TermsOfService } from '../../types'
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { assertTypeIs } from '../../utils/type-assertion' import { assertTypeIs } from '../../utils/type-assertion'
import { normalizePhoneNumber } from '../../utils/misc-utils' import { normalizePhoneNumber } from '../../utils/misc-utils'

View file

@ -1,5 +1,6 @@
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { Chat, MtCuteTypeAssertionError } from '../../types' import { Chat, MtCuteTypeAssertionError } from '../../types'
import { assertIsUpdatesGroup } from '../../utils/updates-utils'
/** /**
* Create a new broadcast channel * Create a new broadcast channel
@ -21,13 +22,7 @@ export async function createChannel(
broadcast: true, broadcast: true,
}) })
if (!(res._ === 'updates' || res._ === 'updatesCombined')) { assertIsUpdatesGroup('channels.createChannel', res)
throw new MtCuteTypeAssertionError(
'channels.createChannel',
'updates | updatesCombined',
res._
)
}
this._handleUpdate(res) this._handleUpdate(res)

View file

@ -3,6 +3,7 @@ import { MaybeArray } from '@mtcute/core'
import { Chat, InputPeerLike, MtCuteTypeAssertionError } from '../../types' import { Chat, InputPeerLike, MtCuteTypeAssertionError } from '../../types'
import { normalizeToInputUser } from '../../utils/peer-utils' import { normalizeToInputUser } from '../../utils/peer-utils'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { assertIsUpdatesGroup } from '../../utils/updates-utils'
/** /**
* Create a legacy group chat * Create a legacy group chat
@ -34,13 +35,7 @@ export async function createGroup(
users: peers users: peers
}) })
if (!(res._ === 'updates' || res._ === 'updatesCombined')) { assertIsUpdatesGroup('messages.createChat', res)
throw new MtCuteTypeAssertionError(
'messages.createChat',
'updates | updatesCombined',
res._
)
}
this._handleUpdate(res) this._handleUpdate(res)

View file

@ -1,5 +1,6 @@
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { Chat, MtCuteTypeAssertionError } from '../../types' import { Chat, MtCuteTypeAssertionError } from '../../types'
import { assertIsUpdatesGroup } from '../../utils/updates-utils'
/** /**
* Create a new supergroup * Create a new supergroup
@ -20,13 +21,7 @@ export async function createSupergroup(
megagroup: true megagroup: true
}) })
if (!(res._ === 'updates' || res._ === 'updatesCombined')) { assertIsUpdatesGroup('channels.createChannel', res)
throw new MtCuteTypeAssertionError(
'channels.createChannel',
'updates | updatesCombined',
res._
)
}
this._handleUpdate(res) this._handleUpdate(res)

View file

@ -3,6 +3,7 @@ import { Chat, MtCuteTypeAssertionError } from '../../types'
import { assertTypeIs } from '../../utils/type-assertion' import { assertTypeIs } from '../../utils/type-assertion'
import { getMarkedPeerId } from '@mtcute/core' import { getMarkedPeerId } from '@mtcute/core'
import { tl } from 'packages/tl' import { tl } from 'packages/tl'
import { assertIsUpdatesGroup } from '../../utils/updates-utils'
/** /**
* Get nearby chats * Get nearby chats
@ -25,13 +26,7 @@ export async function getNearbyChats(
}, },
}) })
if (!(res._ === 'updates' || res._ === 'updatesCombined')) { assertIsUpdatesGroup('contacts.getLocated', res)
throw new MtCuteTypeAssertionError(
'contacts.getLocated',
'updates | updatesCombined',
res._
)
}
if (!res.updates.length) return [] if (!res.updates.length) return []

View file

@ -1,5 +1,6 @@
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { ChatMember, InputPeerLike } from '../../types' import { ChatMember, InputPeerLike } from '../../types'
import { isInputPeerChat } from '../../utils/peer-utils'
/** /**
* Iterate through chat members * Iterate through chat members
@ -45,7 +46,7 @@ export async function* iterChatMembers(
if (!members.length) break if (!members.length) break
if (chat._ === 'inputPeerChat') { if (isInputPeerChat(chat)) {
total = members.length total = members.length
} }

View file

@ -9,6 +9,7 @@ import {
INVITE_LINK_REGEX, INVITE_LINK_REGEX,
normalizeToInputChannel, normalizeToInputChannel,
} from '../../utils/peer-utils' } from '../../utils/peer-utils'
import { assertIsUpdatesGroup } from '../../utils/updates-utils'
/** /**
* Join a channel or supergroup * Join a channel or supergroup
@ -29,13 +30,7 @@ export async function joinChat(
_: 'messages.importChatInvite', _: 'messages.importChatInvite',
hash: m[1], hash: m[1],
}) })
if (!(res._ === 'updates' || res._ === 'updatesCombined')) { assertIsUpdatesGroup('messages.importChatInvite', res)
throw new MtCuteTypeAssertionError(
'messages.importChatInvite',
'updates | updatesCombined',
res._
)
}
this._handleUpdate(res) this._handleUpdate(res)
@ -50,13 +45,8 @@ export async function joinChat(
_: 'channels.joinChannel', _: 'channels.joinChannel',
channel: peer, channel: peer,
}) })
if (!(res._ === 'updates' || res._ === 'updatesCombined')) {
throw new MtCuteTypeAssertionError( assertIsUpdatesGroup('channels.joinChannel', res)
'channels.joinChannel',
'updates | updatesCombined',
res._
)
}
this._handleUpdate(res) this._handleUpdate(res)

View file

@ -1,6 +1,7 @@
import { TelegramClient } from '../../client' import { TelegramClient } from '../../client'
import { Chat, InputPeerLike, MtCuteTypeAssertionError } from '../../types' import { Chat, InputPeerLike, MtCuteTypeAssertionError } from '../../types'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { assertIsUpdatesGroup } from '../../utils/updates-utils'
/** /**
* Change default chat permissions for all members. * Change default chat permissions for all members.
@ -32,13 +33,7 @@ export async function setChatDefaultPermissions(
} }
}) })
if (!(res._ === 'updates' || res._ === 'updatesCombined')) { assertIsUpdatesGroup('messages.editChatDefaultBannedRights', res)
throw new MtCuteTypeAssertionError(
'messages.editChatDefaultBannedRights',
'updates | updatesCombined',
res._
)
}
this._handleUpdate(res) this._handleUpdate(res)

View file

@ -2,6 +2,7 @@ import { TelegramClient } from '../../client'
import { InputPeerLike, MtCuteInvalidPeerTypeError, MtCuteTypeAssertionError, User } from '../../types' import { InputPeerLike, MtCuteInvalidPeerTypeError, MtCuteTypeAssertionError, User } from '../../types'
import { normalizeToInputUser } from '../../utils/peer-utils' import { normalizeToInputUser } from '../../utils/peer-utils'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { assertIsUpdatesGroup } from '../../utils/updates-utils'
/** /**
* Add an existing Telegram user as a contact * Add an existing Telegram user as a contact
@ -48,12 +49,7 @@ export async function addContact(
addPhonePrivacyException: !!params.sharePhone addPhonePrivacyException: !!params.sharePhone
}) })
if (!(res._ === 'updates' || res._ === 'updatesCombined')) assertIsUpdatesGroup('contacts.addContact', res)
throw new MtCuteTypeAssertionError(
'addContact',
'updates | updatesCombined',
res._
)
this._handleUpdate(res) this._handleUpdate(res)

View file

@ -3,6 +3,7 @@ import { MaybeArray } from '@mtcute/core'
import { InputPeerLike, MtCuteInvalidPeerTypeError, MtCuteTypeAssertionError, User } from '../../types' import { InputPeerLike, MtCuteInvalidPeerTypeError, MtCuteTypeAssertionError, User } from '../../types'
import { normalizeToInputUser } from '../../utils/peer-utils' import { normalizeToInputUser } from '../../utils/peer-utils'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { assertIsUpdatesGroup } from '../../utils/updates-utils'
/** /**
* Delete a single contact from your Telegram contacts list * Delete a single contact from your Telegram contacts list
@ -56,12 +57,7 @@ export async function deleteContacts(
id: inputPeers id: inputPeers
}) })
if (!(res._ === 'updates' || res._ === 'updatesCombined')) assertIsUpdatesGroup('contacts.deleteContacts', res)
throw new MtCuteTypeAssertionError(
'addContact',
'updates | updatesCombined',
res._
)
if (single && !res.updates.length) return null if (single && !res.updates.length) return null

View file

@ -3,6 +3,7 @@ import { InputPeerLike, MtCuteTypeAssertionError, Poll } from '../../types'
import { createUsersChatsIndex } from '../../utils/peer-utils' import { createUsersChatsIndex } from '../../utils/peer-utils'
import bigInt from 'big-integer' import bigInt from 'big-integer'
import { assertTypeIs } from '../../utils/type-assertion' import { assertTypeIs } from '../../utils/type-assertion'
import { assertIsUpdatesGroup } from '../../utils/updates-utils'
/** /**
* Close a poll sent by you. * Close a poll sent by you.
@ -35,12 +36,7 @@ export async function closePoll(
}, },
}) })
if (!(res._ === 'updates' || res._ === 'updatesCombined')) assertIsUpdatesGroup('messages.editMessage', res)
throw new MtCuteTypeAssertionError(
'messages.editMessage',
'updates | updatesCombined',
res._
)
this._handleUpdate(res, true) this._handleUpdate(res, true)

View file

@ -2,6 +2,7 @@ import { TelegramClient } from '../../client'
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { Message, MtCuteTypeAssertionError } from '../../types' import { Message, MtCuteTypeAssertionError } from '../../types'
import { createUsersChatsIndex } from '../../utils/peer-utils' import { createUsersChatsIndex } from '../../utils/peer-utils'
import { assertIsUpdatesGroup } from '../../utils/updates-utils'
/** @internal */ /** @internal */
export function _findMessageInUpdate( export function _findMessageInUpdate(
@ -9,12 +10,7 @@ export function _findMessageInUpdate(
res: tl.TypeUpdates, res: tl.TypeUpdates,
isEdit = false isEdit = false
): Message { ): Message {
if (!(res._ === 'updates' || res._ === 'updatesCombined')) assertIsUpdatesGroup('_findMessageInUpdate', res)
throw new MtCuteTypeAssertionError(
'_findMessageInUpdate',
'updates | updatesCombined',
res._
)
this._handleUpdate(res, true) this._handleUpdate(res, true)

View file

@ -12,6 +12,7 @@ import {
createUsersChatsIndex, createUsersChatsIndex,
} from '../../utils/peer-utils' } from '../../utils/peer-utils'
import { normalizeDate, randomUlong } from '../../utils/misc-utils' import { normalizeDate, randomUlong } from '../../utils/misc-utils'
import { assertIsUpdatesGroup } from '../../utils/updates-utils'
/** /**
* Forward a single message. * Forward a single message.
@ -229,12 +230,7 @@ export async function forwardMessages(
), ),
}) })
if (!(res._ === 'updates' || res._ === 'updatesCombined')) assertIsUpdatesGroup('messages.forwardMessages', res)
throw new MtCuteTypeAssertionError(
'messages.forwardMessages',
'updates | updatesCombined',
res._
)
this._handleUpdate(res, true) this._handleUpdate(res, true)
@ -242,12 +238,12 @@ export async function forwardMessages(
const forwarded: Message[] = [] const forwarded: Message[] = []
res.updates.forEach((upd) => { res.updates.forEach((upd) => {
if ( switch (upd._) {
upd._ === 'updateNewMessage' || case 'updateNewMessage':
upd._ == 'updateNewChannelMessage' || case 'updateNewChannelMessage':
upd._ === 'updateNewScheduledMessage' case 'updateNewScheduledMessage':
) { forwarded.push(new Message(this, upd.message, users, chats))
forwarded.push(new Message(this, upd.message, users, chats)) break
} }
}) })

View file

@ -8,6 +8,7 @@ import {
import { MaybeArray } from '@mtcute/core' import { MaybeArray } from '@mtcute/core'
import { createUsersChatsIndex } from '../../utils/peer-utils' import { createUsersChatsIndex } from '../../utils/peer-utils'
import { assertTypeIs } from '../../utils/type-assertion' import { assertTypeIs } from '../../utils/type-assertion'
import { assertIsUpdatesGroup } from '../../utils/updates-utils'
/** /**
* Send or retract a vote in a poll. * Send or retract a vote in a poll.
@ -56,12 +57,7 @@ export async function sendVote(
options: options as Buffer[], options: options as Buffer[],
}) })
if (!(res._ === 'updates' || res._ === 'updatesCombined')) assertIsUpdatesGroup('messages.sendVote', res)
throw new MtCuteTypeAssertionError(
'messages.sendVote',
'updates | updatesCombined',
res._
)
this._handleUpdate(res, true) this._handleUpdate(res, true)

View file

@ -160,37 +160,37 @@ function _createNoDispatchIndex(
pts: {}, pts: {},
} }
if (updates._ === 'updates' || updates._ === 'updatesCombined') { switch (updates._) {
updates.updates.forEach((upd) => { case 'updates':
const cid = extractChannelIdFromUpdate(upd) ?? 0 case 'updatesCombined':
if ( updates.updates.forEach((upd) => {
upd._ === 'updateNewMessage' || const cid = extractChannelIdFromUpdate(upd) ?? 0
upd._ === 'updateNewChannelMessage' switch (upd._) {
) { case 'updateNewMessage':
if (!ret.msg[cid]) ret.msg[cid] = {} case 'updateNewChannelMessage':
ret.msg[cid][upd.message.id] = true if (!ret.msg[cid]) ret.msg[cid] = {}
} ret.msg[cid][upd.message.id] = true
break
}
const pts = 'pts' in upd ? upd.pts : undefined const pts = 'pts' in upd ? upd.pts : undefined
if (pts) { if (pts) {
if (!ret.msg[cid]) ret.msg[cid] = {} if (!ret.msg[cid]) ret.msg[cid] = {}
ret.msg[cid][pts] = true ret.msg[cid][pts] = true
} }
}) })
} break
case 'updateShortMessage':
case 'updateShortChatMessage':
case 'updateShortSentMessage':
// these updates are only used for non-channel messages, so we use 0
if (!ret.msg[0]) ret.msg[0] = {}
if (!ret.pts[0]) ret.pts[0] = {}
if ( ret.msg[0][updates.id] = true
updates._ === 'updateShortMessage' || ret.pts[0][updates.pts] = true
updates._ === 'updateShortChatMessage' || break
updates._ === 'updateShortSentMessage'
) {
// these updates are only used for non-channel messages, so we use 0
if (!ret.msg[0]) ret.msg[0] = {}
if (!ret.pts[0]) ret.pts[0] = {}
ret.msg[0][updates.id] = true
ret.pts[0][updates.pts] = true
} }
return ret return ret
@ -208,11 +208,12 @@ async function _loadDifference(
qts: 0, qts: 0,
}) })
if (diff._ === 'updates.differenceEmpty') return switch (diff._) {
case 'updates.differenceEmpty':
if (diff._ === 'updates.differenceTooLong') { return
this._pts = diff.pts case 'updates.differenceTooLong':
return this._pts = diff.pts
return
} }
const state = const state =

View file

@ -231,88 +231,80 @@ export namespace BotInlineMessage {
obj: InputInlineMessage, obj: InputInlineMessage,
parseMode?: string | null parseMode?: string | null
): Promise<tl.TypeInputBotInlineMessage> { ): Promise<tl.TypeInputBotInlineMessage> {
if (obj.type === 'text') { switch (obj.type) {
const [message, entities] = await client['_parseEntities']( case 'text': {
obj.text, const [message, entities] = await client['_parseEntities'](
parseMode, obj.text,
obj.entities parseMode,
) obj.entities
)
return { return {
_: 'inputBotInlineMessageText', _: 'inputBotInlineMessageText',
message, message,
entities, entities,
replyMarkup: BotKeyboard._convertToTl(obj.replyMarkup), replyMarkup: BotKeyboard._convertToTl(obj.replyMarkup),
}
} }
} case 'media': {
const [message, entities] = await client['_parseEntities'](
obj.text,
parseMode,
obj.entities
)
if (obj.type === 'media') { return {
const [message, entities] = await client['_parseEntities']( _: 'inputBotInlineMessageMediaAuto',
obj.text, message,
parseMode, entities,
obj.entities replyMarkup: BotKeyboard._convertToTl(obj.replyMarkup),
) }
return {
_: 'inputBotInlineMessageMediaAuto',
message,
entities,
replyMarkup: BotKeyboard._convertToTl(obj.replyMarkup),
} }
case 'geo':
case 'geo_live':
return {
_: 'inputBotInlineMessageMediaGeo',
geoPoint: {
_: 'inputGeoPoint',
lat: obj.latitude,
long: obj.longitude,
},
// fields will be `undefined` if this is a `geo`
heading: (obj as InputMediaGeoLive).heading,
period: (obj as InputMediaGeoLive).period,
proximityNotificationRadius: (obj as InputMediaGeoLive)
.proximityNotificationRadius,
replyMarkup: BotKeyboard._convertToTl(obj.replyMarkup),
}
case 'venue':
return {
_: 'inputBotInlineMessageMediaVenue',
geoPoint: {
_: 'inputGeoPoint',
lat: obj.latitude,
long: obj.longitude,
},
title: obj.title,
address: obj.address,
provider: obj.source?.provider ?? '',
venueId: obj.source?.id ?? '',
venueType: obj.source?.type ?? '',
replyMarkup: BotKeyboard._convertToTl(obj.replyMarkup),
}
case 'game':
return {
_: 'inputBotInlineMessageGame',
replyMarkup: BotKeyboard._convertToTl(obj.replyMarkup),
}
case 'contact':
return {
_: 'inputBotInlineMessageMediaContact',
phoneNumber: obj.phone,
firstName: obj.firstName,
lastName: obj.lastName ?? '',
vcard: obj.vcard ?? '',
replyMarkup: BotKeyboard._convertToTl(obj.replyMarkup),
}
} }
if (obj.type === 'geo' || obj.type === 'geo_live') {
return {
_: 'inputBotInlineMessageMediaGeo',
geoPoint: {
_: 'inputGeoPoint',
lat: obj.latitude,
long: obj.longitude,
},
// fields will be `undefined` if this is a `geo`
heading: (obj as InputMediaGeoLive).heading,
period: (obj as InputMediaGeoLive).period,
proximityNotificationRadius: (obj as InputMediaGeoLive)
.proximityNotificationRadius,
replyMarkup: BotKeyboard._convertToTl(obj.replyMarkup),
}
}
if (obj.type === 'venue') {
return {
_: 'inputBotInlineMessageMediaVenue',
geoPoint: {
_: 'inputGeoPoint',
lat: obj.latitude,
long: obj.longitude,
},
title: obj.title,
address: obj.address,
provider: obj.source?.provider ?? '',
venueId: obj.source?.id ?? '',
venueType: obj.source?.type ?? '',
replyMarkup: BotKeyboard._convertToTl(obj.replyMarkup),
}
}
if (obj.type === 'game') {
return {
_: 'inputBotInlineMessageGame',
replyMarkup: BotKeyboard._convertToTl(obj.replyMarkup),
}
}
if (obj.type === 'contact') {
return {
_: 'inputBotInlineMessageMediaContact',
phoneNumber: obj.phone,
firstName: obj.firstName,
lastName: obj.lastName ?? '',
vcard: obj.vcard ?? '',
replyMarkup: BotKeyboard._convertToTl(obj.replyMarkup),
}
}
return obj as never
} }
} }

View file

@ -332,38 +332,31 @@ export namespace BotKeyboard {
): tl.TypeReplyMarkup | undefined { ): tl.TypeReplyMarkup | undefined {
if (!obj) return obj if (!obj) return obj
if (obj.type === 'reply') { switch (obj.type) {
return { case 'reply':
_: 'replyKeyboardMarkup', return {
resize: obj.resize, _: 'replyKeyboardMarkup',
singleUse: obj.singleUse, resize: obj.resize,
selective: obj.selective, singleUse: obj.singleUse,
rows: _2dToRows(obj.buttons), selective: obj.selective,
} rows: _2dToRows(obj.buttons),
}
case 'reply_hide':
return {
_: 'replyKeyboardHide',
selective: obj.selective,
}
case 'force_reply':
return {
_: 'replyKeyboardForceReply',
singleUse: obj.singleUse,
selective: obj.selective,
}
case 'inline':
return {
_: 'replyInlineMarkup',
rows: _2dToRows(obj.buttons),
}
} }
if (obj.type === 'reply_hide') {
return {
_: 'replyKeyboardHide',
selective: obj.selective,
}
}
if (obj.type === 'force_reply') {
return {
_: 'replyKeyboardForceReply',
singleUse: obj.singleUse,
selective: obj.selective,
}
}
if (obj.type === 'inline') {
return {
_: 'replyInlineMarkup',
rows: _2dToRows(obj.buttons),
}
}
return undefined
} }
} }

View file

@ -12,28 +12,26 @@ export function parseDocument(
doc: tl.RawDocument doc: tl.RawDocument
): RawDocument { ): RawDocument {
for (const attr of doc.attributes) { for (const attr of doc.attributes) {
if (attr._ === 'documentAttributeAudio') { switch (attr._) {
if (attr.voice) { case 'documentAttributeAudio':
return new Voice(client, doc, attr) if (attr.voice) {
} else { return new Voice(client, doc, attr)
return new Audio(client, doc, attr) } else {
return new Audio(client, doc, attr)
}
case 'documentAttributeSticker': {
const sz = doc.attributes.find(
(it) => it._ === 'documentAttributeImageSize'
)! as tl.RawDocumentAttributeImageSize
return new Sticker(client, doc, attr, sz)
} }
} case 'documentAttributeVideo':
return new Video(client, doc, attr)
if (attr._ === 'documentAttributeSticker') { case 'documentAttributeImageSize':
const sz = doc.attributes.find( // legacy gif
(it) => it._ === 'documentAttributeImageSize' if (doc.mimeType === 'image/gif') {
)! as tl.RawDocumentAttributeImageSize return new Video(client, doc, attr)
return new Sticker(client, doc, attr, sz) }
}
if (
attr._ === 'documentAttributeVideo' ||
// legacy gif
(attr._ === 'documentAttributeImageSize' &&
doc.mimeType === 'image/gif')
) {
return new Video(client, doc, attr)
} }
} }

View file

@ -62,12 +62,15 @@ export class Thumbnail extends FileLocation {
media: tl.RawPhoto | tl.RawDocument, media: tl.RawPhoto | tl.RawDocument,
sz: tl.TypePhotoSize sz: tl.TypePhotoSize
) { ) {
if (sz._ === 'photoSizeEmpty' || sz._ === 'photoCachedSize') switch (sz._) {
throw new MtCuteTypeAssertionError( case 'photoSizeEmpty':
'sz', case 'photoCachedSize':
'not (photoSizeEmpty | photoCachedSize)', throw new MtCuteTypeAssertionError(
sz._ 'sz',
) 'not (photoSizeEmpty | photoCachedSize)',
sz._
)
}
let location: let location:
| tl.TypeInputFileLocation | tl.TypeInputFileLocation

View file

@ -170,12 +170,16 @@ export class Dialog {
const peer = this.raw.peer const peer = this.raw.peer
let chat let chat
if (peer._ === 'peerChannel' || peer._ === 'peerChat') { switch (peer._) {
chat = this._chats[ case 'peerChannel':
peer._ === 'peerChannel' ? peer.channelId : peer.chatId case 'peerChat':
] chat = this._chats[
} else { peer._ === 'peerChannel' ? peer.channelId : peer.chatId
chat = this._users[peer.userId] ]
break
default:
chat = this._users[peer.userId]
break
} }
this._chat = new Chat(this.client, chat) this._chat = new Chat(this.client, chat)

View file

@ -184,20 +184,27 @@ export class Message {
if (!from) { if (!from) {
// anon admin, return the chat // anon admin, return the chat
this._sender = this.chat this._sender = this.chat
} else if (from._ === 'peerChannel') {
// forwarded channel post
this._sender = new Chat(
this.client,
this._chats[from.channelId]
)
} else if (from._ === 'peerUser') {
this._sender = new User(this.client, this._users[from.userId])
} else } else
throw new MtCuteTypeAssertionError( switch (from._) {
'raw.fromId', case 'peerChannel': // forwarded channel post
'peerUser | peerChannel', this._sender = new Chat(
from._ this.client,
) this._chats[from.channelId]
)
break
case 'peerUser':
this._sender = new User(
this.client,
this._users[from.userId]
)
break
default:
throw new MtCuteTypeAssertionError(
'raw.fromId',
'peerUser | peerChannel',
from._
)
}
} }
return this._sender return this._sender

View file

@ -38,7 +38,7 @@ export class ChatMember {
constructor( constructor(
client: TelegramClient, client: TelegramClient,
raw: tl.TypeChatParticipant | tl.TypeChannelParticipant, raw: tl.TypeChatParticipant | tl.TypeChannelParticipant,
users: UsersIndex, users: UsersIndex
) { ) {
this.client = client this.client = client
this.raw = raw this.raw = raw
@ -51,24 +51,25 @@ export class ChatMember {
*/ */
get user(): User { get user(): User {
if (this._user === undefined) { if (this._user === undefined) {
if ( switch (this.raw._) {
this.raw._ === 'channelParticipantBanned' || case 'channelParticipantBanned':
this.raw._ === 'channelParticipantLeft' case 'channelParticipantLeft':
) { assertTypeIs(
assertTypeIs( 'ChatMember#user (raw.peer)',
'ChatMember#user (raw.peer)', this.raw.peer,
this.raw.peer, 'peerUser'
'peerUser' )
) this._user = new User(
this._user = new User( this.client,
this.client, this._users[this.raw.peer.userId]
this._users[this.raw.peer.userId] )
) break
} else { default:
this._user = new User( this._user = new User(
this.client, this.client,
this._users[this.raw.userId] this._users[this.raw.userId]
) )
break
} }
} }
@ -79,34 +80,23 @@ export class ChatMember {
* Get the chat member status * Get the chat member status
*/ */
get status(): ChatMember.Status { get status(): ChatMember.Status {
if ( switch (this.raw._) {
this.raw._ === 'channelParticipant' || case 'channelParticipant':
this.raw._ === 'channelParticipantSelf' || case 'channelParticipantSelf':
this.raw._ === 'chatParticipant' case 'chatParticipant':
) { return 'member'
return 'member' case 'channelParticipantCreator':
} case 'chatParticipantCreator':
return 'creator'
if ( case 'channelParticipantAdmin':
this.raw._ === 'channelParticipantCreator' || case 'chatParticipantAdmin':
this.raw._ === 'chatParticipantCreator' return 'admin'
) { case 'channelParticipantLeft':
return 'creator' return 'left'
} case 'channelParticipantBanned':
return this.raw.bannedRights.viewMessages
if ( ? 'banned'
this.raw._ === 'channelParticipantAdmin' || : 'restricted'
this.raw._ === 'chatParticipantAdmin'
) {
return 'admin'
}
if (this.raw._ === 'channelParticipantLeft') {
return 'left'
}
if (this.raw._ === 'channelParticipantBanned') {
return this.raw.bannedRights.viewMessages ? 'banned' : 'restricted'
} }
// fallback // fallback
@ -119,10 +109,13 @@ export class ChatMember {
* `null` for non-admins and in case custom title is not set. * `null` for non-admins and in case custom title is not set.
*/ */
get title(): string | null { get title(): string | null {
return this.raw._ === 'channelParticipantCreator' || switch (this.raw._) {
this.raw._ === 'channelParticipantAdmin' case 'channelParticipantCreator':
? this.raw.rank ?? null case 'channelParticipantAdmin':
: null return this.raw.rank ?? null
default:
return null
}
} }
/** /**
@ -131,11 +124,14 @@ export class ChatMember {
* Not available for creators and left members * Not available for creators and left members
*/ */
get joinedDate(): Date | null { get joinedDate(): Date | null {
return this.raw._ === 'channelParticipantCreator' || switch (this.raw._) {
this.raw._ === 'chatParticipantCreator' || case 'channelParticipantCreator':
this.raw._ === 'channelParticipantLeft' case 'chatParticipantCreator':
? null case 'channelParticipantLeft':
: new Date(this.raw.date * 1000) return null
default:
return new Date(this.raw.date * 1000)
}
} }
private _invitedBy?: User | null private _invitedBy?: User | null
@ -149,14 +145,7 @@ export class ChatMember {
*/ */
get invitedBy(): User | null { get invitedBy(): User | null {
if (this._invitedBy === undefined) { if (this._invitedBy === undefined) {
if ( if ('inviterId' in this.raw && this.raw.inviterId) {
this.raw._ !== 'chatParticipantCreator' &&
this.raw._ !== 'channelParticipantCreator' &&
this.raw._ !== 'channelParticipant' &&
this.raw._ !== 'channelParticipantBanned' &&
this.raw._ !== 'channelParticipantLeft' &&
this.raw.inviterId
) {
this._invitedBy = new User( this._invitedBy = new User(
this.client, this.client,
this._users[this.raw.inviterId] this._users[this.raw.inviterId]
@ -244,10 +233,13 @@ export class ChatMember {
* Also contains whether this admin is anonymous. * Also contains whether this admin is anonymous.
*/ */
get permissions(): tl.RawChatAdminRights | null { get permissions(): tl.RawChatAdminRights | null {
return this.raw._ === 'channelParticipantAdmin' || switch (this.raw._) {
this.raw._ === 'channelParticipantCreator' case 'channelParticipantAdmin':
? this.raw.adminRights case 'channelParticipantCreator':
: null return this.raw.adminRights
default:
return null
}
} }
} }

View file

@ -56,20 +56,20 @@ export class Chat {
) { ) {
if (!peer) throw new MtCuteArgumentError('peer is not available') if (!peer) throw new MtCuteArgumentError('peer is not available')
if ( switch (peer._) {
!( case 'user':
peer._ === 'user' || case 'chat':
peer._ === 'chat' || case 'channel':
peer._ === 'channel' || case 'chatForbidden':
peer._ === 'chatForbidden' || case 'channelForbidden':
peer._ === 'channelForbidden' break
) default:
) throw new MtCuteTypeAssertionError(
throw new MtCuteTypeAssertionError( 'peer',
'peer', 'user | chat | channel',
'user | chat | channel', peer._
peer._ )
) }
this.client = client this.client = client
this.peer = peer this.peer = peer
@ -87,41 +87,41 @@ export class Chat {
*/ */
get inputPeer(): tl.TypeInputPeer { get inputPeer(): tl.TypeInputPeer {
if (!this._inputPeer) { if (!this._inputPeer) {
if (this.peer._ === 'user') { switch (this.peer._) {
if (!this.peer.accessHash) { case 'user':
throw new MtCuteArgumentError( if (!this.peer.accessHash) {
"Peer's access hash is not available!" throw new MtCuteArgumentError(
) "Peer's access hash is not available!"
} )
}
this._inputPeer = { this._inputPeer = {
_: 'inputPeerUser', _: 'inputPeerUser',
userId: this.peer.id, userId: this.peer.id,
accessHash: this.peer.accessHash, accessHash: this.peer.accessHash,
} }
} else if ( break
this.peer._ === 'chat' || case 'chat':
this.peer._ === 'chatForbidden' case 'chatForbidden':
) { this._inputPeer = {
this._inputPeer = { _: 'inputPeerChat',
_: 'inputPeerChat', chatId: this.peer.id,
chatId: this.peer.id, }
} break
} else if ( case 'channel':
this.peer._ === 'channel' || case 'channelForbidden':
this.peer._ === 'channelForbidden' if (!this.peer.accessHash) {
) { throw new MtCuteArgumentError(
if (!this.peer.accessHash) { "Peer's access hash is not available!"
throw new MtCuteArgumentError( )
"Peer's access hash is not available!" }
)
}
this._inputPeer = { this._inputPeer = {
_: 'inputPeerChannel', _: 'inputPeerChannel',
channelId: this.peer.id, channelId: this.peer.id,
accessHash: this.peer.accessHash, accessHash: this.peer.accessHash,
} }
break
} }
} }
@ -132,23 +132,23 @@ export class Chat {
/** Type of chat */ /** Type of chat */
get type(): Chat.Type { get type(): Chat.Type {
if (!this._type) { if (!this._type) {
if (this.peer._ === 'user') { switch (this.peer._) {
this._type = this.peer.bot ? 'bot' : 'private' case 'user':
} else if ( this._type = this.peer.bot ? 'bot' : 'private'
this.peer._ === 'chat' || break
this.peer._ === 'chatForbidden' case 'chat':
) { case 'chatForbidden':
this._type = 'group' this._type = 'group'
} else if ( break
this.peer._ === 'channel' || case 'channel':
this.peer._ === 'channelForbidden' case 'channelForbidden':
) { this._type =
this._type = this.peer._ === 'channel' && this.peer.gigagroup
this.peer._ === 'channel' && this.peer.gigagroup ? 'gigagroup'
? 'gigagroup' : this.peer.broadcast
: this.peer.broadcast ? 'channel'
? 'channel' : 'supergroup'
: 'supergroup' break
} }
} }
@ -467,12 +467,11 @@ export class Chat {
users: UsersIndex, users: UsersIndex,
chats: ChatsIndex chats: ChatsIndex
): Chat { ): Chat {
if (peer._ === 'peerUser') { switch (peer._) {
return new Chat(client, users[peer.userId]) case 'peerUser':
} return new Chat(client, users[peer.userId])
case 'peerChat':
if (peer._ === 'peerChat') { return new Chat(client, chats[peer.chatId])
return new Chat(client, chats[peer.chatId])
} }
return new Chat(client, chats[peer.channelId]) return new Chat(client, chats[peer.channelId])
@ -508,8 +507,6 @@ export class Chat {
} }
} }
// todo: bound methods https://github.com/pyrogram/pyrogram/blob/a86656aefcc93cc3d2f5c98227d5da28fcddb136/pyrogram/types/user_and_chats/chat.py#L319
/** /**
* Join this chat. * Join this chat.
*/ */

View file

@ -1,4 +1,5 @@
import { tl } from '@mtcute/tl' import { tl } from '@mtcute/tl'
import { MtCuteTypeAssertionError } from '../types'
// dummy updates which are used for methods that return messages.affectedHistory. // dummy updates which are used for methods that return messages.affectedHistory.
// that is not an update, but it carries info about pts, and we need to handle it // that is not an update, but it carries info about pts, and we need to handle it
@ -34,3 +35,13 @@ export function isDummyUpdate(upd: tl.TypeUpdate): boolean {
export function isDummyUpdates(upd: tl.TypeUpdates): boolean { export function isDummyUpdates(upd: tl.TypeUpdates): boolean {
return upd._ === 'updates' && upd.updates.length === 1 && isDummyUpdate(upd.updates[0]) return upd._ === 'updates' && upd.updates.length === 1 && isDummyUpdate(upd.updates[0])
} }
/** @internal */
export function assertIsUpdatesGroup(ctx: string, upd: tl.TypeUpdates): asserts upd is tl.RawUpdates | tl.RawUpdatesCombined {
switch (upd._) {
case 'updates':
case 'updatesCombined':
return
}
throw new MtCuteTypeAssertionError(ctx, 'updates | updatesCombined', upd._)
}

View file

@ -10,11 +10,14 @@ export const MAX_USER_ID = 2147483647
* Get the bare (non-marked) ID from a {@link tl.TypePeer} * Get the bare (non-marked) ID from a {@link tl.TypePeer}
*/ */
export function getBarePeerId(peer: tl.TypePeer): number { export function getBarePeerId(peer: tl.TypePeer): number {
if (peer._ === 'peerUser') return peer.userId switch (peer._) {
if (peer._ === 'peerChat') return peer.chatId case 'peerUser':
if (peer._ === 'peerChannel') return peer.channelId return peer.userId
case 'peerChat':
throw new Error('Invalid peer') return peer.chatId
case 'peerChannel':
return peer.channelId
}
} }
/** /**
@ -35,17 +38,31 @@ export function getMarkedPeerId(
peerType?: BasicPeerType | PeerType peerType?: BasicPeerType | PeerType
): number { ): number {
if (typeof peer === 'number') { if (typeof peer === 'number') {
if (peerType === 'user' || peerType === 'bot') return peer switch (peerType) {
if (peerType === 'chat' || peerType === 'group') return -peer case 'user':
if (peerType === 'channel' || peerType === 'supergroup') case 'bot':
return MAX_CHANNEL_ID - peer return peer
case 'chat':
case 'group':
return -peer
case 'channel':
case 'supergroup':
return MAX_CHANNEL_ID - peer
}
throw new Error('Invalid peer type') throw new Error('Invalid peer type')
} }
if (peer._ === 'peerUser' || peer._ === 'inputPeerUser') return peer.userId switch (peer._) {
if (peer._ === 'peerChat' || peer._ === 'inputPeerChat') return -peer.chatId case 'peerUser':
if (peer._ === 'peerChannel' || peer._ === 'inputPeerChannel') case 'inputPeerUser':
return MAX_CHANNEL_ID - peer.channelId return peer.userId
case 'peerChat':
case 'inputPeerChat':
return -peer.chatId
case 'peerChannel':
case 'inputPeerChannel':
return MAX_CHANNEL_ID - peer.channelId
}
throw new Error('Invalid peer') throw new Error('Invalid peer')
} }
@ -55,11 +72,14 @@ export function getMarkedPeerId(
*/ */
export function getBasicPeerType(peer: tl.TypePeer | number): BasicPeerType { export function getBasicPeerType(peer: tl.TypePeer | number): BasicPeerType {
if (typeof peer !== 'number') { if (typeof peer !== 'number') {
if (peer._ === 'peerUser') return 'user' switch (peer._) {
if (peer._ === 'peerChat') return 'chat' case 'peerUser':
if (peer._ === 'peerChannel') return 'channel' return 'user'
case 'peerChat':
throw new Error('Invalid peer') return 'chat'
case 'peerChannel':
return 'channel'
}
} }
if (peer < 0) { if (peer < 0) {
@ -90,11 +110,16 @@ export function markedPeerIdToBare(peerId: number): number {
* Convert {@link PeerType} to {@link BasicPeerType} * Convert {@link PeerType} to {@link BasicPeerType}
*/ */
export function peerTypeToBasic(type: PeerType): BasicPeerType { export function peerTypeToBasic(type: PeerType): BasicPeerType {
if (type === 'bot' || type === 'user') return 'user' switch (type) {
if (type === 'group') return 'chat' case 'bot':
if (type === 'channel' || type === 'supergroup') return 'channel' case 'user':
return 'user'
throw new Error('Invalid peer type') case 'group':
return 'chat'
case 'channel':
case 'supergroup':
return 'channel'
}
} }
function comparePeers( function comparePeers(
@ -105,22 +130,28 @@ function comparePeers(
if ('userId' in first) { if ('userId' in first) {
if ('userId' in second) return first.userId === second.userId if ('userId' in second) return first.userId === second.userId
if (second._ === 'user' || second._ === 'userEmpty') switch (second._) {
return first.userId === second.id case 'user':
case 'userEmpty':
return first.userId === second.id
}
} }
if ('chatId' in first) { if ('chatId' in first) {
if ('chatId' in second) return first.chatId === second.chatId if ('chatId' in second) return first.chatId === second.chatId
if ( switch (second._) {
second._ === 'chat' || case 'chat':
second._ === 'chatForbidden' || case 'chatForbidden':
second._ === 'chatEmpty' case 'chatEmpty':
) return first.chatId === second.id
return first.chatId === second.id }
} }
if ('channelId' in first) { if ('channelId' in first) {
if ('channelId' in second) return first.channelId === second.channelId if ('channelId' in second) return first.channelId === second.channelId
if (second._ === 'channel' || second._ === 'channelForbidden') switch (second._) {
return first.channelId === second.id case 'channel':
case 'channelForbidden':
return first.channelId === second.id
}
} }
return false return false
} }
@ -141,31 +172,32 @@ function isRefMessage(msg: tl.TypeMessage, peer: any): boolean | undefined {
function findContext(obj: any, peer: any): [number, number] | undefined { function findContext(obj: any, peer: any): [number, number] | undefined {
if (!peer.min) return undefined if (!peer.min) return undefined
if ( switch (obj._) {
obj._ === 'updates' || case 'updates':
obj._ === 'updatesCombined' || case 'updatesCombined':
obj._ === 'updates.difference' || case 'updates.difference':
obj._ === 'updates.differenceSlice' case 'updates.differenceSlice':
) { for (const upd of (obj.updates ||
for (const upd of (obj.updates || obj.otherUpdates) as tl.TypeUpdate[]) { obj.otherUpdates) as tl.TypeUpdate[]) {
if ( switch (upd._) {
(upd._ === 'updateNewMessage' || case 'updateNewMessage':
upd._ === 'updateNewChannelMessage' || case 'updateNewChannelMessage':
upd._ === 'updateEditMessage' || case 'updateEditMessage':
upd._ === 'updateEditChannelMessage') && case 'updateEditChannelMessage':
isRefMessage(upd.message, peer) if (isRefMessage(upd.message, peer)) {
) { return [
return [getMarkedPeerId(upd.message.peerId!), upd.message.id] getMarkedPeerId(upd.message.peerId!),
upd.message.id,
]
}
break
}
} }
} break
} case 'updateShortMessage':
return [obj.userId, obj.id]
if (obj._ === 'updateShortMessage') { case 'updateShortChatMessage':
return [obj.userId, obj.id] return [-obj.chatId, obj.id]
}
if (obj._ === 'updateShortChatMessage') {
return [-obj.chatId, obj.id]
} }
if ('messages' in obj || 'newMessages' in obj) { if ('messages' in obj || 'newMessages' in obj) {
@ -193,19 +225,17 @@ export function* getAllPeersFrom(
> { > {
if (typeof obj !== 'object') return if (typeof obj !== 'object') return
if ( switch (obj._) {
obj._ === 'user' || case 'user':
obj._ === 'chat' || case 'chat':
obj._ === 'channel' || case 'channel':
obj._ === 'chatForbidden' || case 'chatForbidden':
obj._ === 'channelForbidden' case 'channelForbidden':
) { yield obj
yield obj return
return case 'userFull':
} yield obj.user
if (obj._ === 'userFull') { return
yield obj.user
return
} }
if ( if (
@ -216,26 +246,26 @@ export function* getAllPeersFrom(
yield obj.user yield obj.user
} }
if ( if ('chat' in obj && typeof obj.chat === 'object') {
'chat' in obj && switch (obj.chat._) {
typeof obj.chat === 'object' && case 'chat':
(obj.chat._ === 'chat' || case 'channel':
obj.chat._ === 'channel' || case 'chatForbidden':
obj.chat._ === 'chatForbidden' || case 'channelForbidden':
obj.chat._ === 'channelForbidden') yield obj.chat
) { break
yield obj.chat }
} }
if ( if ('channel' in obj && typeof obj.channel === 'object') {
'channel' in obj && switch (obj.channel._) {
typeof obj.channel === 'object' && case 'chat':
(obj.channel._ === 'chat' || case 'channel':
obj.channel._ === 'channel' || case 'chatForbidden':
obj.channel._ === 'chatForbidden' || case 'channelForbidden':
obj.channel._ === 'channelForbidden') yield obj.channel
) { break
yield obj.channel }
} }
if ('users' in obj && Array.isArray(obj.users) && obj.users.length) { if ('users' in obj && Array.isArray(obj.users) && obj.users.length) {
@ -257,18 +287,19 @@ export function* getAllPeersFrom(
if ('chats' in obj && Array.isArray(obj.chats) && obj.chats.length) { if ('chats' in obj && Array.isArray(obj.chats) && obj.chats.length) {
for (const chat of obj.chats) { for (const chat of obj.chats) {
// .chats is sometimes number[] // .chats is sometimes number[]
if ( if (typeof chat === 'object') {
typeof chat === 'object' && switch (chat._) {
(chat._ === 'chat' || case 'chat':
chat._ === 'channel' || case 'channel':
chat._ === 'chatForbidden' || case 'chatForbidden':
chat._ === 'channelForbidden') case 'channelForbidden':
) { if (chat.min) {
if (chat.min) { chat.fromMessage = findContext(obj, chat)
chat.fromMessage = findContext(obj, chat) }
}
yield chat yield chat
break
}
} }
} }
} }

View file

@ -38,14 +38,16 @@ export function jsonToTlJson(obj: any): tl.TypeJSONValue {
* @param obj TL JSON object to convert * @param obj TL JSON object to convert
*/ */
export function tlJsonToJson(obj: tl.TypeJSONValue): any { export function tlJsonToJson(obj: tl.TypeJSONValue): any {
if (obj._ === 'jsonNull') return null switch (obj._) {
if ( case 'jsonNull':
obj._ === 'jsonBool' || return null
obj._ === 'jsonNumber' || case 'jsonBool':
obj._ === 'jsonString' case 'jsonNumber':
) case 'jsonString':
return obj.value return obj.value
if (obj._ === 'jsonArray') return obj.value.map(tlJsonToJson) case 'jsonArray':
return obj.value.map(tlJsonToJson)
}
const ret: any = {} const ret: any = {}

View file

@ -127,20 +127,29 @@ export class ChatMemberUpdate {
// in this case OR is the same as AND, but AND doesn't work well with typescript :shrug: // in this case OR is the same as AND, but AND doesn't work well with typescript :shrug:
if (!old || !cur) return (this._type = 'other') if (!old || !cur) return (this._type = 'other')
if (old._ === 'chatParticipant' || old._ === 'channelParticipant') { switch (old._) {
if ( case 'chatParticipant':
cur._ === 'chatParticipantAdmin' || case 'channelParticipant':
cur._ === 'channelParticipantAdmin' switch (cur._) {
) { case 'chatParticipantAdmin':
return (this._type = 'promoted') case 'channelParticipantAdmin':
} return (this._type = 'promoted')
case 'channelParticipantBanned':
// kicked or restricted
if (cur.left) return (this._type = 'kicked')
if (cur._ === 'channelParticipantBanned') { return (this._type = 'restricted')
// kicked or restricted }
if (cur.left) return (this._type = 'kicked') break
case 'chatParticipantCreator':
case 'channelParticipantCreator':
return (this._type = 'old_owner')
}
return (this._type = 'restricted') switch (cur._) {
} case 'chatParticipantCreator':
case 'channelParticipantCreator':
return (this._type = 'new_owner')
} }
if ( if (
@ -157,20 +166,6 @@ export class ChatMemberUpdate {
return (this._type = 'demoted') return (this._type = 'demoted')
} }
if (
old._ === 'chatParticipantCreator' ||
old._ === 'channelParticipantCreator'
) {
return (this._type = 'old_owner')
}
if (
cur._ === 'chatParticipantCreator' ||
cur._ === 'channelParticipantCreator'
) {
return (this._type = 'new_owner')
}
return (this._type = 'other') return (this._type = 'other')
} }

View file

@ -75,25 +75,29 @@ export function toUniqueFileId(
} }
let writer: BinaryWriter let writer: BinaryWriter
if (inputLocation._ === 'photo') { switch (inputLocation._) {
writer = BinaryWriter.alloc(16) case 'photo':
writer.int32(type) writer = BinaryWriter.alloc(16)
writer.long(inputLocation.volumeId) writer.int32(type)
writer.int32(inputLocation.localId) writer.long(inputLocation.volumeId)
} else if (inputLocation._ === 'web') { writer.int32(inputLocation.localId)
writer = BinaryWriter.alloc( break
Buffer.byteLength(inputLocation.url, 'utf-8') + 8 case 'web':
) writer = BinaryWriter.alloc(
writer.int32(type) Buffer.byteLength(inputLocation.url, 'utf-8') + 8
writer.string(inputLocation.url) )
} else if (inputLocation._ === 'common') { writer.int32(type)
writer = BinaryWriter.alloc(12) writer.string(inputLocation.url)
writer.int32(type) break
writer.long(inputLocation.id) case 'common':
} else { writer = BinaryWriter.alloc(12)
throw new td.UnsupportedError( writer.int32(type)
`Unique IDs are not supported for ${(inputLocation as any)._}` writer.long(inputLocation.id)
) break
default:
throw new td.UnsupportedError(
`Unique IDs are not supported for ${(inputLocation as any)._}`
)
} }
return encodeUrlSafeBase64(telegramRleEncode(writer.result())) return encodeUrlSafeBase64(telegramRleEncode(writer.result()))