diff --git a/.vscode/settings.json b/.vscode/settings.json index 5c08bf9..6395058 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,7 +7,8 @@ "Google", "Tests", "Upgrade", - "Config" + "Config", + "Container" ], "typescript.preferences.importModuleSpecifier": "non-relative", "vitest.commandLine": "yarn test:watch", diff --git a/package.json b/package.json index 3f8ec09..6c96bd2 100644 --- a/package.json +++ b/package.json @@ -85,6 +85,7 @@ "@odg/message": "*", "dotenv": "^16.4.5", "inversify": "^6.1.4", + "inversify-binding-decorators": "^4.0.0", "playwright": "^1.49.0", "playwright-core": "^1.49.0", "reflect-metadata": "^0.2.2", diff --git a/src/Console/Kernel.ts b/src/Console/Kernel.ts index 530a9e3..f0a7b7b 100644 --- a/src/Console/Kernel.ts +++ b/src/Console/Kernel.ts @@ -1,7 +1,8 @@ import { randomUUID } from "node:crypto"; import { LoggerInterface } from "@odg/log"; -import { inject, injectable } from "inversify"; +import { inject } from "inversify"; +import { fluentProvide } from "inversify-binding-decorators"; import { chromium } from "playwright-core"; import { ContainerInterface } from "#types"; @@ -15,7 +16,7 @@ import { ProcessKernel } from "~/Console/ProcessKernel"; * * @class Kernel */ -@injectable() +@(fluentProvide(ContainerName.Kernel).inSingletonScope().done()) export class Kernel { public constructor( diff --git a/src/Console/ProcessKernel.ts b/src/Console/ProcessKernel.ts index 6b1d882..3d82ac5 100644 --- a/src/Console/ProcessKernel.ts +++ b/src/Console/ProcessKernel.ts @@ -1,9 +1,10 @@ -import { inject, injectable } from "inversify"; +import { inject } from "inversify"; +import { fluentProvide } from "inversify-binding-decorators"; import Container from "@app/Container"; import { ContainerName } from "@enums"; -@injectable() +@(fluentProvide(ContainerName.ProcessKernel).inSingletonScope().done()) export class ProcessKernel { public constructor( diff --git a/src/Handlers/GoogleSearch/GoogleSearchHandler.ts b/src/Handlers/GoogleSearch/GoogleSearchHandler.ts index 0806b8b..e854293 100644 --- a/src/Handlers/GoogleSearch/GoogleSearchHandler.ts +++ b/src/Handlers/GoogleSearch/GoogleSearchHandler.ts @@ -3,14 +3,14 @@ import { type HandlerFunction, HandlerSolution, RetryAction, + ContainerHelper, } from "@odg/chemical-x"; import { type Exception } from "@odg/exception"; -import { injectable } from "inversify"; -import { ConfigName, EventName } from "@enums"; +import { ConfigName, ContainerName, EventName } from "@enums"; import { BaseHandler } from "@handlers/BaseHandler"; -@injectable() +@ContainerHelper.injectablePage(ContainerName.SearchHandlerFactory) export class GoogleSearchToSelectionHandler extends BaseHandler implements HandlerInterface { public async waitForHandler(): Promise { diff --git a/src/Interfaces/BasePageInterface.ts b/src/Interfaces/BasePageInterface.ts deleted file mode 100644 index 3a59b8e..0000000 --- a/src/Interfaces/BasePageInterface.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { type HandlerInterface, type PageInterface } from "@odg/chemical-x"; - -import { type PageClassEngine } from "../engine"; - -export type BasePageInterface = new(page: PageClassEngine) => HandlerInterface | PageInterface; diff --git a/src/Interfaces/index.ts b/src/Interfaces/index.ts new file mode 100644 index 0000000..5a2a770 --- /dev/null +++ b/src/Interfaces/index.ts @@ -0,0 +1 @@ +export interface Example {} diff --git a/src/Pages/BasePage.ts b/src/Pages/BasePage.ts index 0a8366a..2aec55f 100644 --- a/src/Pages/BasePage.ts +++ b/src/Pages/BasePage.ts @@ -1,14 +1,13 @@ import { BasePage as ChemicalBasePage } from "@odg/chemical-x"; import { ConfigInterface } from "@odg/config"; import { type LoggerInterface } from "@odg/log"; -import { inject, injectable } from "inversify"; +import { inject } from "inversify"; import { type ConfigType } from "@configs"; import { type PageClassEngine } from "@engine"; import { ContainerName } from "@enums"; import * as Selectors from "@selectors"; -@injectable() export abstract class BasePage extends ChemicalBasePage { @inject(ContainerName.Logger) diff --git a/src/Pages/Google/SearchPage.ts b/src/Pages/Google/SearchPage.ts index 79ce423..4aad9da 100644 --- a/src/Pages/Google/SearchPage.ts +++ b/src/Pages/Google/SearchPage.ts @@ -1,16 +1,15 @@ import crypto from "node:crypto"; -import { type PageInterface } from "@odg/chemical-x"; -import { injectable } from "inversify"; +import { ContainerHelper, type PageInterface } from "@odg/chemical-x"; -import { ConfigName } from "@app/Enums"; +import { ConfigName, ContainerName } from "@app/Enums"; import { BasePage } from "@pages/BasePage"; import { type GoogleSearchSelectorType, googleSearchSelector, } from "@selectors"; -@injectable() +@ContainerHelper.injectablePage(ContainerName.SearchPageFactory) export class SearchPage extends BasePage implements PageInterface { public readonly $s: GoogleSearchSelectorType = googleSearchSelector; diff --git a/src/app/Container.ts b/src/app/Container.ts index 72835f5..b4a41df 100644 --- a/src/app/Container.ts +++ b/src/app/Container.ts @@ -3,9 +3,8 @@ import { type CreateContextFactoryType, type CreatePageFactoryType, BrowserManager, - type HandlerInterface, - type PageInterface, type ContextChemicalXInterface, + ContainerHelper, } from "@odg/chemical-x"; import { JsonConfig } from "@odg/config"; import { EventEmitterBus } from "@odg/events"; @@ -14,43 +13,42 @@ import { ConsoleLogger, Logger } from "@odg/log"; import { Container as ContainerInversify, decorate, injectable, type interfaces, } from "inversify"; +import { buildProviderModule } from "inversify-binding-decorators"; import { type ContainerNameType, type ContainerType, type EventTypes } from "#types"; import { type ConfigType, configValidator } from "@configs"; import { ConfigName, ContainerName } from "@enums"; -import { type PageOrHandlerFactoryType } from "@factory"; -import { GoogleSearchToSelectionHandler } from "@handlers/GoogleSearch/GoogleSearchHandler"; -import { type BasePageInterface } from "@interfaces/BasePageInterface"; -import { SearchEventListener } from "@listeners/SearchEventListener"; -import { SearchPage } from "@pages/Google/SearchPage"; -import { EventServiceProvider } from "@providers/EventServiceProvider"; -import { ExampleCrawlerService } from "@services/ExampleCrawlerService"; import { Browser, Context, Page } from "../Browser"; -import { Kernel, ProcessKernel } from "../Console"; import { type BrowserClassEngine, type ContextClassEngine, type PageClassEngine, } from "../engine"; +import "../Console"; +import "@listeners"; +import "@handlers"; +import "@pages"; +import "@providers"; +import "@services"; + export default class Container { public readonly container: ContainerInversify; - private pageContainerNumber = 0; - public constructor() { this.container = new ContainerInversify({ skipBaseClassChecks: true }); } public async setUp(): Promise { await this.prepareInjectable(); + this.container.load(buildProviderModule()); + this.container.load(ContainerHelper.loadModule(this.container)); await this.bindCrawler(); await this.bindKernel(); await this.initBeginKernel(); await this.bindStanley(); - await this.bindEventsAndListeners(); } /** @@ -150,25 +148,10 @@ export default class Container { ContainerName.ConsoleLogger, ).to(ConsoleLogger).inSingletonScope(); - // Event Provider - this.bind( - ContainerName.EventServiceProvider, - ).to(EventServiceProvider).inSingletonScope(); - // Container instance this.bind( ContainerName.Container, ).toDynamicValue(() => this).inSingletonScope(); - - // Kernel Inject Service - this.bind( - ContainerName.ProcessKernel, - ).to(ProcessKernel).inSingletonScope(); - - // Kernel Inject Service - this.bind( - ContainerName.Kernel, - ).to(Kernel).inSingletonScope(); } /** @@ -185,27 +168,15 @@ export default class Container { ContainerName.Requester, ).to(AxiosMessage).inSingletonScope(); - // Example Service - this.bind( - ContainerName.ExampleCrawlerService, - ).to(ExampleCrawlerService).inSingletonScope(); - const appName = await this.get(ContainerName.Config).get(ConfigName.APP_NAME); this.bind( ContainerName.JSONLogger, ).toDynamicValue(() => new JSONLoggerPlugin(appName ?? "unknown")).inSingletonScope(); - } - private async bindEventsAndListeners(): Promise { // EventBus Interface this.bind( ContainerName.EventBus, ).to(EventEmitterBus).inSingletonScope(); - - // SearchGoogle Listeners bind - this.bind( - ContainerName.SearchEventListeners, - ).to(SearchEventListener).inSingletonScope(); } private async bindCrawler(): Promise { @@ -227,38 +198,6 @@ export default class Container { pageEngine: PageClassEngine, ) => new Page(context, pageEngine), )); - - // SearchPage Google - this.bind(ContainerName.SearchPageFactory) - .toFactory(() => this.instancePageOrHandler(SearchPage)); - - // SearchHandler Google - this.bind(ContainerName.SearchHandlerFactory) - .toFactory(() => this.instancePageOrHandler( - GoogleSearchToSelectionHandler, - )); - } - - /** - * Use To instance a page and handler Crawler - * - * @template {PageInterface} PageType - * @memberof Container - * @param {BasePageInterface} BasePagePrepare Page Class instantiable - * @returns {PageOrHandlerFactoryType} - */ - private instancePageOrHandler( - BasePagePrepare: BasePageInterface, - ): PageOrHandlerFactoryType { - return (page: PageClassEngine): PageType => { - const container = `PageOrHandler${this.pageContainerNumber++}`; - this.container.bind(container).to(BasePagePrepare); - const value = this.container.get(container); - this.container.unbind(container); - (value as unknown as { page: unknown }).page = page; - - return value; - }; } } diff --git a/src/app/Listeners/SearchEventListener.ts b/src/app/Listeners/SearchEventListener.ts index 17d0df9..7d26674 100644 --- a/src/app/Listeners/SearchEventListener.ts +++ b/src/app/Listeners/SearchEventListener.ts @@ -1,13 +1,14 @@ import { type EventListenerInterface } from "@odg/events"; import { LoggerInterface } from "@odg/log"; -import { inject, injectable } from "inversify"; +import { inject } from "inversify"; +import { fluentProvide } from "inversify-binding-decorators"; import { type EventBrowserParameters, type EventTypes } from "#types/EventsInterface"; import { ContainerName, type EventName } from "@enums"; import { PageOrHandlerFactoryType } from "@factory"; import { type SearchPage } from "@pages/Google/SearchPage"; -@injectable() +@(fluentProvide(ContainerName.SearchEventListeners).inSingletonScope().done()) export class SearchEventListener implements EventListenerInterface { public constructor( diff --git a/src/app/Provider/EventServiceProvider.ts b/src/app/Provider/EventServiceProvider.ts index 66839ed..d003206 100644 --- a/src/app/Provider/EventServiceProvider.ts +++ b/src/app/Provider/EventServiceProvider.ts @@ -4,8 +4,9 @@ import { type EventListener, } from "@odg/events"; import { - inject, injectable, + inject, } from "inversify"; +import { fluentProvide } from "inversify-binding-decorators"; import { type EventTypes } from "#types/EventsInterface"; import { ContainerName, EventName } from "@enums"; @@ -17,7 +18,7 @@ import Container from "../Container"; * * @template {EventTypes} Events Events List */ -@injectable() +@(fluentProvide(ContainerName.EventServiceProvider).inSingletonScope().done()) export class EventServiceProvider extends EventServiceProviderBase { /** diff --git a/src/app/Provider/index.ts b/src/app/Provider/index.ts new file mode 100644 index 0000000..354098f --- /dev/null +++ b/src/app/Provider/index.ts @@ -0,0 +1 @@ +export * from "./EventServiceProvider"; diff --git a/src/app/Services/ExampleCrawlerService.ts b/src/app/Services/ExampleCrawlerService.ts index 5940dfa..24f1a89 100644 --- a/src/app/Services/ExampleCrawlerService.ts +++ b/src/app/Services/ExampleCrawlerService.ts @@ -1,6 +1,7 @@ import { EventBusInterface } from "@odg/events"; import { LoggerInterface } from "@odg/log"; -import { inject, injectable } from "inversify"; +import { inject } from "inversify"; +import { fluentProvide } from "inversify-binding-decorators"; import { type EventTypes } from "#types/EventsInterface"; import { MyBrowser } from "@engine"; @@ -9,7 +10,7 @@ import { ContainerName, EventName } from "@enums"; import { type GoogleSearchToSelectionHandler } from "../../Handlers/GoogleSearch/GoogleSearchHandler"; import { PageOrHandlerFactoryType } from "../Factory"; -@injectable() +@(fluentProvide(ContainerName.ExampleCrawlerService).inSingletonScope().done()) export class ExampleCrawlerService { public constructor( diff --git a/src/app/Services/index.ts b/src/app/Services/index.ts new file mode 100644 index 0000000..437ef58 --- /dev/null +++ b/src/app/Services/index.ts @@ -0,0 +1 @@ +export * from "./ExampleCrawlerService"; diff --git a/tests/vitest/Containers/ContainerDynamic.test.ts b/tests/vitest/Containers/ContainerDynamic.test.ts index 329b126..7344652 100644 --- a/tests/vitest/Containers/ContainerDynamic.test.ts +++ b/tests/vitest/Containers/ContainerDynamic.test.ts @@ -1,7 +1,7 @@ import * as Engine from "@engine"; import { ContainerName } from "@enums"; import * as Factory from "@factory"; -import * as BasePageInterface from "@interfaces/BasePageInterface"; +import * as BasePageInterface from "@interfaces"; import { container } from "../SingletonTest"; diff --git a/yarn.lock b/yarn.lock index 1e6e4e6..d697014 100644 --- a/yarn.lock +++ b/yarn.lock @@ -582,20 +582,23 @@ axios "*" "@odg/chemical-x@*": - version "1.14.0" - resolved "https://registry.yarnpkg.com/@odg/chemical-x/-/chemical-x-1.14.0.tgz#2f85d853252d7153ada1ef4ad885dcb8aaf3bbcf" - integrity sha512-9tu7yDYCpSR1y7BHCL80fhiMRGFsg8BCuHwA4ajwcn2Zip2+13omqOT8/fq2OPl83UjJqLpR9Gah4/H+dmltNw== + version "1.15.0" + resolved "https://registry.yarnpkg.com/@odg/chemical-x/-/chemical-x-1.15.0.tgz#4a304c0f8b2d24c5fea1cc55f4c142568f35f9e8" + integrity sha512-cpZ5JQyEODn9e6/7JjJ2Te1oZ3BG4nncb1O9eYZwr8EBcj9vTiyc1FmOKyZ9HH4qvOQCEN+QEK7sOHf53dfnKA== dependencies: "@odg/exception" "*" + optionalDependencies: + inversify "^6.1.4" + reflect-metadata "^0.2.2" "@odg/command@*": - version "1.7.1" - resolved "https://registry.yarnpkg.com/@odg/command/-/command-1.7.1.tgz#3965d8f17ea1aabde627a9f402761b41708f115a" - integrity sha512-g5SFVsz3vMNKFDcEp6CBgjjUD+oFaV94HcpekEx5+Z8vIzePftcBeE3ypA08CAWDyzUuNk5xI2vXnKaZenXE3g== + version "1.8.0" + resolved "https://registry.yarnpkg.com/@odg/command/-/command-1.8.0.tgz#c81af037ca677f94e01e4fb95ccea303d217bade" + integrity sha512-jU+y8nK3lV4pPLlGpsZfvpnvOXAC3BD0kJsXdhHPjT/GKyMmcj92Cz4CyU63YA4UIDVGSybR4XNDuaMkAld4mw== dependencies: "@odg/chemical-x" "*" "@odg/exception" "*" - commander "^11.0.0" + commander "^12.1.0" "@odg/config@*": version "1.1.2" @@ -1508,21 +1511,16 @@ combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" -commander@^11.0.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-11.1.0.tgz#62fdce76006a68e5c1ab3314dc92e800eb83d906" - integrity sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ== +commander@^12.1.0, commander@~12.1.0: + version "12.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3" + integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA== commander@^9.0.0: version "9.5.0" resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30" integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ== -commander@~12.1.0: - version "12.1.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3" - integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA== - comment-parser@*, comment-parser@1.4.1, comment-parser@^1.4.0: version "1.4.1" resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.4.1.tgz#bdafead37961ac079be11eb7ec65c4d021eaf9cc" @@ -2891,6 +2889,11 @@ internal-slot@^1.0.7: hasown "^2.0.0" side-channel "^1.0.4" +inversify-binding-decorators@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/inversify-binding-decorators/-/inversify-binding-decorators-4.0.0.tgz#c4d1ac50d7d6531f465ee7894e92031f7471c865" + integrity sha512-r8au/oH3vS7ttHj0RivAznwElySeRohLfg8lvOSzbrX6abf/8ik8ptk49XbzdShgrnalvl7CM6MjcskfM7MMqQ== + inversify@^6.1.4: version "6.1.4" resolved "https://registry.yarnpkg.com/inversify/-/inversify-6.1.4.tgz#7dc288b190bc6c0e2081d7a003cbf6c4f94d946f" @@ -4564,9 +4567,9 @@ tree-kill@^1.2.2: integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== ts-api-utils@^1.0.1, ts-api-utils@^1.3.0: - version "1.4.2" - resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.4.2.tgz#a6a6dff26117ac7965624fc118525971edc6a82a" - integrity sha512-ZF5gQIQa/UmzfvxbHZI3JXN0/Jt+vnAfAviNRAMc491laiK6YCLpCW9ft8oaCRFOTxCZtUTE6XB0ZQAe3olntw== + version "1.4.3" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.4.3.tgz#bfc2215fe6528fecab2b0fba570a2e8a4263b064" + integrity sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw== tsc-alias@^1.8.10: version "1.8.10"