refactor: use type discrimination for media types in Message
this should result in cleaner code without the need to import everything
This commit is contained in:
parent
abbebeddf9
commit
d0e3ebda80
16 changed files with 72 additions and 33 deletions
|
@ -8,6 +8,8 @@ import { tdFileId } from '@mtcute/file-id'
|
||||||
* An audio file
|
* An audio file
|
||||||
*/
|
*/
|
||||||
export class Audio extends RawDocument {
|
export class Audio extends RawDocument {
|
||||||
|
readonly type = 'audio' as const
|
||||||
|
|
||||||
readonly doc: tl.RawDocument
|
readonly doc: tl.RawDocument
|
||||||
readonly attr: tl.RawDocumentAttributeAudio
|
readonly attr: tl.RawDocumentAttributeAudio
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,8 @@ import { tl } from '@mtcute/tl'
|
||||||
import { makeInspectable } from '../utils'
|
import { makeInspectable } from '../utils'
|
||||||
|
|
||||||
export class Contact {
|
export class Contact {
|
||||||
|
readonly type = 'contact' as const
|
||||||
|
|
||||||
readonly obj: tl.RawMessageMediaContact
|
readonly obj: tl.RawMessageMediaContact
|
||||||
|
|
||||||
constructor(obj: tl.RawMessageMediaContact) {
|
constructor(obj: tl.RawMessageMediaContact) {
|
||||||
|
|
|
@ -5,6 +5,8 @@ import { makeInspectable } from '../utils'
|
||||||
* A dice or another interactive random emoji.
|
* A dice or another interactive random emoji.
|
||||||
*/
|
*/
|
||||||
export class Dice {
|
export class Dice {
|
||||||
|
readonly type = 'dice' as const
|
||||||
|
|
||||||
readonly obj: tl.RawMessageMediaDice
|
readonly obj: tl.RawMessageMediaDice
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -169,6 +169,8 @@ export class RawDocument extends FileLocation {
|
||||||
* and only used for documents without any special
|
* and only used for documents without any special
|
||||||
* attributes.
|
* attributes.
|
||||||
*/
|
*/
|
||||||
export class Document extends RawDocument {}
|
export class Document extends RawDocument {
|
||||||
|
readonly type = 'document' as const
|
||||||
|
}
|
||||||
|
|
||||||
makeInspectable(Document, ['fileSize', 'dcId'], ['inputMedia', 'inputDocument'])
|
makeInspectable(Document, ['fileSize', 'dcId'], ['inputMedia', 'inputDocument'])
|
||||||
|
|
|
@ -5,6 +5,8 @@ import { TelegramClient } from '../../client'
|
||||||
import { makeInspectable } from '../utils'
|
import { makeInspectable } from '../utils'
|
||||||
|
|
||||||
export class Game {
|
export class Game {
|
||||||
|
readonly type = 'game' as const
|
||||||
|
|
||||||
readonly game: tl.RawGame
|
readonly game: tl.RawGame
|
||||||
readonly client: TelegramClient
|
readonly client: TelegramClient
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@ import { MtCuteArgumentError } from '../errors'
|
||||||
* An invoice
|
* An invoice
|
||||||
*/
|
*/
|
||||||
export class Invoice {
|
export class Invoice {
|
||||||
|
readonly type = 'invoice' as const
|
||||||
|
|
||||||
readonly client: TelegramClient
|
readonly client: TelegramClient
|
||||||
readonly raw: tl.RawMessageMediaInvoice
|
readonly raw: tl.RawMessageMediaInvoice
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { TelegramClient } from '../../client'
|
||||||
/**
|
/**
|
||||||
* A point on the map
|
* A point on the map
|
||||||
*/
|
*/
|
||||||
export class Location {
|
export class RawLocation {
|
||||||
readonly client: TelegramClient
|
readonly client: TelegramClient
|
||||||
readonly geo: tl.RawGeoPoint
|
readonly geo: tl.RawGeoPoint
|
||||||
|
|
||||||
|
@ -105,7 +105,13 @@ export class Location {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class LiveLocation extends Location {
|
export class Location extends RawLocation {
|
||||||
|
readonly type = 'location' as const
|
||||||
|
}
|
||||||
|
|
||||||
|
export class LiveLocation extends RawLocation {
|
||||||
|
readonly type = 'live_location' as const
|
||||||
|
|
||||||
readonly live: tl.RawMessageMediaGeoLive
|
readonly live: tl.RawMessageMediaGeoLive
|
||||||
|
|
||||||
constructor(client: TelegramClient, live: tl.RawMessageMediaGeoLive) {
|
constructor(client: TelegramClient, live: tl.RawMessageMediaGeoLive) {
|
||||||
|
|
|
@ -9,6 +9,8 @@ import { makeInspectable } from '../utils'
|
||||||
* A photo
|
* A photo
|
||||||
*/
|
*/
|
||||||
export class Photo extends FileLocation {
|
export class Photo extends FileLocation {
|
||||||
|
readonly type: 'photo'
|
||||||
|
|
||||||
/** Raw TL object */
|
/** Raw TL object */
|
||||||
readonly raw: tl.RawPhoto
|
readonly raw: tl.RawPhoto
|
||||||
|
|
||||||
|
@ -78,6 +80,7 @@ export class Photo extends FileLocation {
|
||||||
this.raw = raw
|
this.raw = raw
|
||||||
this.width = width
|
this.width = width
|
||||||
this.height = height
|
this.height = height
|
||||||
|
this.type = 'photo'
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Date this photo was sent */
|
/** Date this photo was sent */
|
||||||
|
|
|
@ -38,6 +38,8 @@ export namespace Poll {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Poll {
|
export class Poll {
|
||||||
|
readonly type = 'poll' as const
|
||||||
|
|
||||||
readonly client: TelegramClient
|
readonly client: TelegramClient
|
||||||
readonly raw: tl.TypePoll
|
readonly raw: tl.TypePoll
|
||||||
readonly results?: tl.TypePollResults
|
readonly results?: tl.TypePollResults
|
||||||
|
|
|
@ -40,6 +40,8 @@ const MASK_POS = ['forehead', 'eyes', 'mouth', 'chin'] as const
|
||||||
* A sticker
|
* A sticker
|
||||||
*/
|
*/
|
||||||
export class Sticker extends RawDocument {
|
export class Sticker extends RawDocument {
|
||||||
|
readonly type = 'sticker' as const
|
||||||
|
|
||||||
readonly attr: tl.RawDocumentAttributeSticker
|
readonly attr: tl.RawDocumentAttributeSticker
|
||||||
readonly attrSize?: tl.RawDocumentAttributeImageSize
|
readonly attrSize?: tl.RawDocumentAttributeImageSize
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,8 @@ export namespace Venue {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Venue {
|
export class Venue {
|
||||||
|
readonly type = 'venue' as const
|
||||||
|
|
||||||
readonly client: TelegramClient
|
readonly client: TelegramClient
|
||||||
readonly raw: tl.RawMessageMediaVenue
|
readonly raw: tl.RawMessageMediaVenue
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@ import { tdFileId } from '@mtcute/file-id'
|
||||||
* **Note:** Legacy GIF animations are also wrapped with this class.
|
* **Note:** Legacy GIF animations are also wrapped with this class.
|
||||||
*/
|
*/
|
||||||
export class Video extends RawDocument {
|
export class Video extends RawDocument {
|
||||||
|
readonly type = 'video' as const
|
||||||
|
|
||||||
readonly attr:
|
readonly attr:
|
||||||
| tl.RawDocumentAttributeVideo
|
| tl.RawDocumentAttributeVideo
|
||||||
| tl.RawDocumentAttributeImageSize
|
| tl.RawDocumentAttributeImageSize
|
||||||
|
|
|
@ -8,6 +8,8 @@ import { tdFileId } from '@mtcute/file-id'
|
||||||
* An voice note.
|
* An voice note.
|
||||||
*/
|
*/
|
||||||
export class Voice extends RawDocument {
|
export class Voice extends RawDocument {
|
||||||
|
readonly type = 'voice' as const
|
||||||
|
|
||||||
readonly doc: tl.RawDocument
|
readonly doc: tl.RawDocument
|
||||||
readonly attr: tl.RawDocumentAttributeAudio
|
readonly attr: tl.RawDocumentAttributeAudio
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@ import { MtCuteArgumentError } from '../errors'
|
||||||
* of my own observations and experiments.
|
* of my own observations and experiments.
|
||||||
*/
|
*/
|
||||||
export class WebPage {
|
export class WebPage {
|
||||||
|
readonly type = 'web_page' as const
|
||||||
|
|
||||||
readonly client: TelegramClient
|
readonly client: TelegramClient
|
||||||
readonly raw: tl.RawWebPage
|
readonly raw: tl.RawWebPage
|
||||||
|
|
||||||
|
@ -71,7 +73,7 @@ export class WebPage {
|
||||||
*
|
*
|
||||||
* `unknown` is returned if no type is returned in the TL object.
|
* `unknown` is returned if no type is returned in the TL object.
|
||||||
*/
|
*/
|
||||||
get type(): string {
|
get previewType(): string {
|
||||||
return this.raw.type || 'unknown'
|
return this.raw.type || 'unknown'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ export function _messageMediaFromTl(
|
||||||
return new Contact(m)
|
return new Contact(m)
|
||||||
case 'messageMediaDocument':
|
case 'messageMediaDocument':
|
||||||
if (!(m.document?._ === 'document')) return null
|
if (!(m.document?._ === 'document')) return null
|
||||||
return parseDocument(this.client, m.document)
|
return parseDocument(this.client, m.document) as MessageMedia
|
||||||
case 'messageMediaGeo':
|
case 'messageMediaGeo':
|
||||||
if (!(m.geo._ === 'geoPoint')) return null
|
if (!(m.geo._ === 'geoPoint')) return null
|
||||||
return new Location(this.client, m.geo)
|
return new Location(this.client, m.geo)
|
||||||
|
|
|
@ -21,7 +21,7 @@ import {
|
||||||
Invoice,
|
Invoice,
|
||||||
Game,
|
Game,
|
||||||
WebPage,
|
WebPage,
|
||||||
MessageAction
|
MessageAction, RawLocation,
|
||||||
} from '@mtcute/client'
|
} from '@mtcute/client'
|
||||||
import { MaybeArray } from '@mtcute/core'
|
import { MaybeArray } from '@mtcute/core'
|
||||||
import { ChatMemberUpdate } from './updates'
|
import { ChatMemberUpdate } from './updates'
|
||||||
|
@ -52,7 +52,7 @@ import { UserTypingUpdate } from './updates/user-typing-update'
|
||||||
* Example without type mod:
|
* Example without type mod:
|
||||||
* ```typescript
|
* ```typescript
|
||||||
*
|
*
|
||||||
* const hasPhoto: UpdateFilter<Message> = msg => msg.media instanceof Photo
|
* const hasPhoto: UpdateFilter<Message> = msg => msg.media?.type === 'photo'
|
||||||
*
|
*
|
||||||
* // ..later..
|
* // ..later..
|
||||||
* tg.onNewMessage(hasPhoto, async (msg) => {
|
* tg.onNewMessage(hasPhoto, async (msg) => {
|
||||||
|
@ -68,7 +68,7 @@ import { UserTypingUpdate } from './updates/user-typing-update'
|
||||||
* Example with type mod:
|
* Example with type mod:
|
||||||
* ```typescript
|
* ```typescript
|
||||||
*
|
*
|
||||||
* const hasPhoto: UpdateFilter<Message, { media: Photo }> = msg => msg.media instanceof Photo
|
* const hasPhoto: UpdateFilter<Message, { media: Photo }> = msg => msg.media?.type === 'photo'
|
||||||
*
|
*
|
||||||
* // ..later..
|
* // ..later..
|
||||||
* tg.onNewMessage(hasPhoto, async (msg) => {
|
* tg.onNewMessage(hasPhoto, async (msg) => {
|
||||||
|
@ -87,7 +87,7 @@ import { UserTypingUpdate } from './updates/user-typing-update'
|
||||||
* > Bad example:
|
* > Bad example:
|
||||||
* > ```typescript
|
* > ```typescript
|
||||||
* > // we check for `Photo`, but type contains `Audio`. this will be a problem!
|
* > // we check for `Photo`, but type contains `Audio`. this will be a problem!
|
||||||
* > const hasPhoto: UpdateFilter<Message, { media: Audio }> = msg => msg.media instanceof Photo
|
* > const hasPhoto: UpdateFilter<Message, { media: Audio }> = msg => msg.media?.type === 'photo'
|
||||||
* >
|
* >
|
||||||
* > // ..later..
|
* > // ..later..
|
||||||
* > tg.onNewMessage(hasPhoto, async (msg) => {
|
* > tg.onNewMessage(hasPhoto, async (msg) => {
|
||||||
|
@ -595,19 +595,19 @@ export namespace filters {
|
||||||
* Filter messages containing a photo
|
* Filter messages containing a photo
|
||||||
*/
|
*/
|
||||||
export const photo: UpdateFilter<Message, { media: Photo }> = (msg) =>
|
export const photo: UpdateFilter<Message, { media: Photo }> = (msg) =>
|
||||||
msg.media?.constructor === Photo
|
msg.media?.type === 'photo'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter messages containing a dice
|
* Filter messages containing a dice
|
||||||
*/
|
*/
|
||||||
export const dice: UpdateFilter<Message, { media: Dice }> = (msg) =>
|
export const dice: UpdateFilter<Message, { media: Dice }> = (msg) =>
|
||||||
msg.media?.constructor === Dice
|
msg.media?.type === 'dice'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter messages containing a contact
|
* Filter messages containing a contact
|
||||||
*/
|
*/
|
||||||
export const contact: UpdateFilter<Message, { media: Contact }> = (msg) =>
|
export const contact: UpdateFilter<Message, { media: Contact }> = (msg) =>
|
||||||
msg.media?.constructor === Contact
|
msg.media?.type === 'contact'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter messages containing a document
|
* Filter messages containing a document
|
||||||
|
@ -615,7 +615,7 @@ export namespace filters {
|
||||||
* This will also match media like audio, video, voice
|
* This will also match media like audio, video, voice
|
||||||
* that also use Documents
|
* that also use Documents
|
||||||
*/
|
*/
|
||||||
export const rawDocument: UpdateFilter<Message, { media: RawDocument }> = (
|
export const anyDocument: UpdateFilter<Message, { media: RawDocument }> = (
|
||||||
msg
|
msg
|
||||||
) => msg.media instanceof RawDocument
|
) => msg.media instanceof RawDocument
|
||||||
|
|
||||||
|
@ -625,33 +625,33 @@ export namespace filters {
|
||||||
* This will not match media like audio, video, voice
|
* This will not match media like audio, video, voice
|
||||||
*/
|
*/
|
||||||
export const document: UpdateFilter<Message, { media: Document }> = (msg) =>
|
export const document: UpdateFilter<Message, { media: Document }> = (msg) =>
|
||||||
msg.media?.constructor === Document
|
msg.media?.type === 'document'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter messages containing an audio file
|
* Filter messages containing an audio file
|
||||||
*/
|
*/
|
||||||
export const audio: UpdateFilter<Message, { media: Audio }> = (msg) =>
|
export const audio: UpdateFilter<Message, { media: Audio }> = (msg) =>
|
||||||
msg.media?.constructor === Audio
|
msg.media?.type === 'audio'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter messages containing a voice note
|
* Filter messages containing a voice note
|
||||||
*/
|
*/
|
||||||
export const voice: UpdateFilter<Message, { media: Voice }> = (msg) =>
|
export const voice: UpdateFilter<Message, { media: Voice }> = (msg) =>
|
||||||
msg.media?.constructor === Voice
|
msg.media?.type === 'voice'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter messages containing a sticker
|
* Filter messages containing a sticker
|
||||||
*/
|
*/
|
||||||
export const sticker: UpdateFilter<Message, { media: Sticker }> = (msg) =>
|
export const sticker: UpdateFilter<Message, { media: Sticker }> = (msg) =>
|
||||||
msg.media?.constructor === Sticker
|
msg.media?.type === 'sticker'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter messages containing a video.
|
* Filter messages containing a video.
|
||||||
*
|
*
|
||||||
* This includes videos, round messages and animations
|
* This includes videos, round messages and animations
|
||||||
*/
|
*/
|
||||||
export const rawVideo: UpdateFilter<Message, { media: Video }> = (msg) =>
|
export const anyVideo: UpdateFilter<Message, { media: Video }> = (msg) =>
|
||||||
msg.media?.constructor === Video
|
msg.media?.type === 'video'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter messages containing a simple video.
|
* Filter messages containing a simple video.
|
||||||
|
@ -670,7 +670,7 @@ export namespace filters {
|
||||||
>
|
>
|
||||||
}
|
}
|
||||||
> = (msg) =>
|
> = (msg) =>
|
||||||
msg.media?.constructor === Video &&
|
msg.media?.type === 'video' &&
|
||||||
!msg.media.isAnimation &&
|
!msg.media.isAnimation &&
|
||||||
!msg.media.isRound
|
!msg.media.isRound
|
||||||
|
|
||||||
|
@ -692,7 +692,7 @@ export namespace filters {
|
||||||
>
|
>
|
||||||
}
|
}
|
||||||
> = (msg) =>
|
> = (msg) =>
|
||||||
msg.media?.constructor === Video &&
|
msg.media?.type === 'video' &&
|
||||||
msg.media.isAnimation &&
|
msg.media.isAnimation &&
|
||||||
!msg.media.isRound
|
!msg.media.isRound
|
||||||
|
|
||||||
|
@ -711,17 +711,23 @@ export namespace filters {
|
||||||
>
|
>
|
||||||
}
|
}
|
||||||
> = (msg) =>
|
> = (msg) =>
|
||||||
msg.media?.constructor === Video &&
|
msg.media?.type === 'video' &&
|
||||||
!msg.media.isAnimation &&
|
!msg.media.isAnimation &&
|
||||||
msg.media.isRound
|
msg.media.isRound
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter messages containing a location.
|
* Filter messages containing any location (live or static).
|
||||||
*
|
|
||||||
* This includes live locations
|
|
||||||
*/
|
*/
|
||||||
export const location: UpdateFilter<Message, { media: Location }> = (msg) =>
|
export const anyLocation: UpdateFilter<Message, { media: Location }> = (msg) =>
|
||||||
msg.media instanceof Location
|
msg.media instanceof RawLocation
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter messages containing a static (non-live) location.
|
||||||
|
*/
|
||||||
|
export const location: UpdateFilter<
|
||||||
|
Message,
|
||||||
|
{ media: LiveLocation }
|
||||||
|
> = (msg) => msg.media?.type === 'location'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter messages containing a live location.
|
* Filter messages containing a live location.
|
||||||
|
@ -729,37 +735,37 @@ export namespace filters {
|
||||||
export const liveLocation: UpdateFilter<
|
export const liveLocation: UpdateFilter<
|
||||||
Message,
|
Message,
|
||||||
{ media: LiveLocation }
|
{ media: LiveLocation }
|
||||||
> = (msg) => msg.media?.constructor === LiveLocation
|
> = (msg) => msg.media?.type === 'live_location'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter messages containing a game.
|
* Filter messages containing a game.
|
||||||
*/
|
*/
|
||||||
export const game: UpdateFilter<Message, { media: Game }> = (msg) =>
|
export const game: UpdateFilter<Message, { media: Game }> = (msg) =>
|
||||||
msg.media?.constructor === Game
|
msg.media?.type === 'game'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter messages containing a webpage preview.
|
* Filter messages containing a webpage preview.
|
||||||
*/
|
*/
|
||||||
export const webpage: UpdateFilter<Message, { media: WebPage }> = (msg) =>
|
export const webpage: UpdateFilter<Message, { media: WebPage }> = (msg) =>
|
||||||
msg.media?.constructor === WebPage
|
msg.media?.type === 'web_page'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter messages containing a venue.
|
* Filter messages containing a venue.
|
||||||
*/
|
*/
|
||||||
export const venue: UpdateFilter<Message, { media: Venue }> = (msg) =>
|
export const venue: UpdateFilter<Message, { media: Venue }> = (msg) =>
|
||||||
msg.media?.constructor === Venue
|
msg.media?.type === 'venue'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter messages containing a poll.
|
* Filter messages containing a poll.
|
||||||
*/
|
*/
|
||||||
export const poll: UpdateFilter<Message, { media: Poll }> = (msg) =>
|
export const poll: UpdateFilter<Message, { media: Poll }> = (msg) =>
|
||||||
msg.media?.constructor === Poll
|
msg.media?.type === 'poll'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter messages containing an invoice.
|
* Filter messages containing an invoice.
|
||||||
*/
|
*/
|
||||||
export const invoice: UpdateFilter<Message, { media: Invoice }> = (msg) =>
|
export const invoice: UpdateFilter<Message, { media: Invoice }> = (msg) =>
|
||||||
msg.media?.constructor === Invoice
|
msg.media?.type === 'invoice'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter objects that match a given regular expression
|
* Filter objects that match a given regular expression
|
||||||
|
|
Loading…
Reference in a new issue