diff --git a/lib/helpers/create-update-listener-decorator.helper.ts b/lib/helpers/create-update-listener-decorator.helper.ts deleted file mode 100644 index 28343e2..0000000 --- a/lib/helpers/create-update-listener-decorator.helper.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { SetMetadata } from '@nestjs/common'; -import { Composer } from 'telegraf'; -import { ComposerMethodArgs, UpdateMethods } from '../types'; -import { UPDATE_LISTENER_METADATA } from '../telegraf.constants'; -import { ListenerMetadata } from '../interfaces'; - -export function createUpdateListenerDecorator( - method: unknown, -) { - return ( - ...args: ComposerMethodArgs, Method> - ): MethodDecorator => { - return SetMetadata(UPDATE_LISTENER_METADATA, { - method, - args, - } as ListenerMetadata); - }; -} diff --git a/lib/helpers/index.ts b/lib/helpers/index.ts deleted file mode 100644 index 20b6077..0000000 --- a/lib/helpers/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './create-update-listener-decorator.helper'; -export * from './create-scene-listener-decorator.helper'; diff --git a/lib/interfaces/update-metadata.interface.ts b/lib/interfaces/update-metadata.interface.ts deleted file mode 100644 index 4c2ba0e..0000000 --- a/lib/interfaces/update-metadata.interface.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface UpdateMetadata { - name: string; - type: string; - methodName: string; - callback?: Function | Record; -} diff --git a/lib/services/listeners-explorer.service.ts b/lib/services/listeners-explorer.service.ts new file mode 100644 index 0000000..44a9121 --- /dev/null +++ b/lib/services/listeners-explorer.service.ts @@ -0,0 +1,111 @@ +import { Inject, Injectable, OnModuleInit } from '@nestjs/common'; +import { DiscoveryService, ModuleRef, ModulesContainer } from '@nestjs/core'; +import { InstanceWrapper } from '@nestjs/core/injector/instance-wrapper'; +import { MetadataScanner } from '@nestjs/core/metadata-scanner'; +import { Module } from '@nestjs/core/injector/module'; +import { BaseScene, Composer, Stage, Telegraf } from 'telegraf'; + +import { MetadataAccessorService } from './metadata-accessor.service'; +import { TELEGRAF_MODULE_OPTIONS } from '../telegraf.constants'; +import { TelegrafModuleOptions } from '../interfaces'; +import { BaseExplorerService } from './base-explorer.service'; +import { getBotToken } from '../utils'; + +@Injectable() +export class TelegrafExplorerService + extends BaseExplorerService + implements OnModuleInit { + private readonly bot: Telegraf; + private readonly stage = new Stage([]); + + constructor( + @Inject(TELEGRAF_MODULE_OPTIONS) + private readonly telegrafOptions: TelegrafModuleOptions, + private readonly moduleRef: ModuleRef, + private readonly discoveryService: DiscoveryService, + private readonly metadataAccessor: MetadataAccessorService, + private readonly metadataScanner: MetadataScanner, + private readonly modulesContainer: ModulesContainer, + ) { + super(); + + const botToken = getBotToken(this.telegrafOptions.name); + this.bot = this.moduleRef.get>(botToken); + this.bot.use(this.stage.middleware()); + } + + onModuleInit(): void { + this.explore(); + } + + explore(): void { + const modules = this.getModules( + this.modulesContainer, + this.telegrafOptions.include || [], + ); + + this.registerUpdates(modules); + this.registerScenes(modules); + } + + private registerUpdates(modules: Module[]): void { + const updates = this.flatMap(modules, (instance) => + this.filterUpdates(instance), + ); + updates.forEach(({ instance }) => + this.registerInstanceMethodListeners(this.bot, instance), + ); + } + + private registerScenes(modules: Module[]): void { + const scenes = this.flatMap(modules, (instance) => + this.filterScenes(instance), + ); + scenes.forEach(({ instance }) => { + const sceneId = this.metadataAccessor.getSceneMetadata( + instance.constructor, + ); + const scene = new BaseScene(sceneId); + this.stage.register(scene); + + this.registerInstanceMethodListeners(scene, instance); + }); + } + + private filterUpdates(wrapper: InstanceWrapper): InstanceWrapper { + const { instance } = wrapper; + if (!instance) return undefined; + + const isUpdate = this.metadataAccessor.isUpdate(wrapper.metatype); + if (!isUpdate) return undefined; + + return wrapper; + } + + private filterScenes(wrapper: InstanceWrapper): InstanceWrapper { + const { instance } = wrapper; + if (!instance) return undefined; + + const isScene = this.metadataAccessor.isScene(wrapper.metatype); + if (!isScene) return undefined; + + return wrapper; + } + + private registerInstanceMethodListeners( + composer: Composer, + instance: Record, + ): void { + const prototype = Object.getPrototypeOf(instance); + this.metadataScanner.scanFromPrototype(instance, prototype, (name) => { + const methodRef = instance[name]; + + const metadata = this.metadataAccessor.getListenerMetadata(methodRef); + if (!metadata) return; + + const middlewareFn = methodRef.bind(instance); + const { method, args } = metadata; + composer[method](...args, middlewareFn); + }); + } +} diff --git a/lib/services/scenes-explorer.service.ts b/lib/services/scenes-explorer.service.ts deleted file mode 100644 index be3d47d..0000000 --- a/lib/services/scenes-explorer.service.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { Inject, Injectable, OnModuleInit } from '@nestjs/common'; -import { DiscoveryService, ModuleRef, ModulesContainer } from '@nestjs/core'; -import { MetadataScanner } from '@nestjs/core/metadata-scanner'; -import { InstanceWrapper } from '@nestjs/core/injector/instance-wrapper'; -import { BaseScene as Scene, Stage, Telegraf } from 'telegraf'; -import { MetadataAccessorService } from './metadata-accessor.service'; -import { BaseExplorerService } from './base-explorer.service'; -import { - TELEGRAF_BOT_NAME, - TELEGRAF_MODULE_OPTIONS, -} from '../telegraf.constants'; -import { TelegrafModuleOptions } from '../interfaces'; -import { Module } from '@nestjs/core/injector/module'; - -@Injectable() -export class ScenesExplorerService - extends BaseExplorerService - implements OnModuleInit { - private readonly stage = new Stage([]); - - constructor( - @Inject(TELEGRAF_BOT_NAME) - private readonly botName: string, - @Inject(TELEGRAF_MODULE_OPTIONS) - private readonly telegrafModuleOptions: TelegrafModuleOptions, - private readonly moduleRef: ModuleRef, - private readonly discoveryService: DiscoveryService, - private readonly metadataAccessor: MetadataAccessorService, - private readonly metadataScanner: MetadataScanner, - private readonly modulesContainer: ModulesContainer, - ) { - super(); - } - - private bot: Telegraf; - - onModuleInit(): void { - this.bot = this.moduleRef.get>(this.botName, { - strict: false, - }); - this.bot.use(this.stage.middleware()); - this.explore(); - } - - private explore(): void { - const modules = this.getModules( - this.modulesContainer, - this.telegrafModuleOptions.include || [], - ); - const scenes = this.flatMap(modules, (instance, moduleRef) => - this.applyScenes(instance, moduleRef), - ); - } - - private applyScenes(wrapper: InstanceWrapper, moduleRef: Module) { - const { instance } = wrapper; - if (!instance) { - return undefined; - } - const prototype = Object.getPrototypeOf(instance); - - const providers: InstanceWrapper[] = this.discoveryService.getProviders(); - const sceneProviders: InstanceWrapper[] = providers.filter( - (wrapper: InstanceWrapper) => - this.metadataAccessor.isScene(wrapper.metatype), - ); - - sceneProviders.forEach((wrapper) => { - const { instance } = wrapper; - if (!instance) { - return undefined; - } - - const sceneId = this.metadataAccessor.getSceneMetadata( - instance.constructor, - ); - - const scene = new Scene(sceneId); - this.stage.register(scene); - - this.metadataScanner.scanFromPrototype( - instance, - prototype, - (methodKey: string) => { - const methodRef = instance[methodKey]; - if (this.metadataAccessor.isUpdateListener(methodRef)) { - const metadata = this.metadataAccessor.getListenerMetadata( - methodRef, - ); - const middlewareFn = methodRef.bind(instance); - const { method, args } = metadata; - (scene[method] as any)(...args, middlewareFn); - } - }, - ); - }); - } -} diff --git a/lib/services/updates-explorer.service.ts b/lib/services/updates-explorer.service.ts deleted file mode 100644 index 09fa250..0000000 --- a/lib/services/updates-explorer.service.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { Inject, Injectable, OnModuleInit } from '@nestjs/common'; -import { DiscoveryService, ModuleRef, ModulesContainer } from '@nestjs/core'; -import { InstanceWrapper } from '@nestjs/core/injector/instance-wrapper'; -import { MetadataScanner } from '@nestjs/core/metadata-scanner'; -import { MetadataAccessorService } from './metadata-accessor.service'; -import { - TELEGRAF_BOT_NAME, - TELEGRAF_MODULE_OPTIONS, -} from '../telegraf.constants'; -import { Telegraf } from 'telegraf'; -import { TelegrafModuleOptions } from '../interfaces'; -import { BaseExplorerService } from './base-explorer.service'; -import { Module } from '@nestjs/core/injector/module'; - -@Injectable() -export class UpdatesExplorerService - extends BaseExplorerService - implements OnModuleInit { - constructor( - @Inject(TELEGRAF_BOT_NAME) - private readonly botName: string, - @Inject(TELEGRAF_MODULE_OPTIONS) - private readonly telegrafModuleOptions: TelegrafModuleOptions, - private readonly moduleRef: ModuleRef, - private readonly discoveryService: DiscoveryService, - private readonly metadataAccessor: MetadataAccessorService, - private readonly metadataScanner: MetadataScanner, - private readonly modulesContainer: ModulesContainer, - ) { - super(); - } - - private bot: Telegraf; - - onModuleInit(): void { - this.bot = this.moduleRef.get>(this.botName, { - strict: false, - }); - this.explore(); - } - - explore() { - const modules = this.getModules( - this.modulesContainer, - this.telegrafModuleOptions.include || [], - ); - const updates = this.flatMap(modules, (instance, moduleRef) => - this.applyUpdates(instance, moduleRef), - ); - } - - private applyUpdates(wrapper: InstanceWrapper, moduleRef: Module) { - const { instance } = wrapper; - if (!instance) { - return undefined; - } - const prototype = Object.getPrototypeOf(instance); - - const providers: InstanceWrapper[] = this.discoveryService.getProviders(); - const updateProviders: InstanceWrapper[] = providers.filter( - (wrapper: InstanceWrapper) => - this.metadataAccessor.isUpdate(wrapper.metatype), - ); - - updateProviders.forEach((wrapper: InstanceWrapper) => { - const { instance } = wrapper; - if (!instance) { - return undefined; - } - this.metadataScanner.scanFromPrototype(instance, prototype, (name) => { - const methodRef = instance[name]; - if (this.metadataAccessor.isUpdateListener(methodRef)) { - const metadata = this.metadataAccessor.getListenerMetadata(methodRef); - const middlewareFn = methodRef.bind(instance); - const { method, args } = metadata; - // NOTE: Use "any" to disable "Expected at least 1 arguments, but got 1 or more." error. - // Use telegraf instance for non-scene listeners - (this.bot[method] as any)(...args, middlewareFn); - } - }); - }); - } -} diff --git a/lib/helpers/create-scene-listener-decorator.helper.ts b/lib/utils/create-listener-decorator.util.ts similarity index 86% rename from lib/helpers/create-scene-listener-decorator.helper.ts rename to lib/utils/create-listener-decorator.util.ts index b089ebf..82dad7d 100644 --- a/lib/helpers/create-scene-listener-decorator.helper.ts +++ b/lib/utils/create-listener-decorator.util.ts @@ -4,7 +4,7 @@ import { ComposerMethodArgs, SceneMethods } from '../types'; import { UPDATE_LISTENER_METADATA } from '../telegraf.constants'; import { ListenerMetadata } from '../interfaces'; -export function createSceneListenerDecorator( +export function createListenerDecorator( method: Method, ) { return ( diff --git a/package.json b/package.json index fed1366..4c30ab3 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,8 @@ "prepublish:npm": "npm run build", "publish:npm": "npm publish --access public", "test": "", - "typedoc:build": "typedoc --tsconfig ./tsconfig.typedoc.json" + "typedoc:build": "typedoc --tsconfig ./tsconfig.typedoc.json", + "sample-app": "ts-node --transpile-only -r tsconfig-paths/register sample/main.ts" }, "dependencies": { "telegraf": "3.38.0" @@ -50,6 +51,7 @@ "prettier": "2.2.1", "reflect-metadata": "0.1.13", "rxjs": "6.6.3", + "tsconfig-paths": "3.9.0", "typedoc": "0.20.9", "typescript": "4.1.3" }, diff --git a/tsconfig.json b/tsconfig.json index d12ec66..9e322c9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,8 +7,9 @@ "noLib": false, "emitDecoratorMetadata": true, "experimentalDecorators": true, - "target": "es6", + "target": "es2017", "sourceMap": false, + "baseUrl": "./", "outDir": "./dist", "skipLibCheck": true },