diff --git a/package.json b/package.json index d5d39a4..034393d 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ ], "scripts": { "build": "tsc -p ./tsconfig.build.json", - "test": "jest --coverage --detectOpenHandles", + "test": "jest --coverage --detectOpenHandles --testTimeout=15000", "ci": "npm run lint && npm run test", "lint:fix": "eslint . --ext .ts --fix", "lint": "eslint . --ext .ts" diff --git a/src/constant.ts b/src/constant.ts index 51be2b3..2b15f23 100644 --- a/src/constant.ts +++ b/src/constant.ts @@ -14,16 +14,22 @@ export enum ArtusInjectEnum { Trigger = 'artus#trigger', } -export const ARTUS_EXCEPTION_DEFAULT_LOCALE = 'en'; - -export const ARTUS_SERVER_ENV = 'ARTUS_SERVER_ENV'; - export enum ARTUS_DEFAULT_CONFIG_ENV { DEV = 'development', PROD = 'production', DEFAULT = 'default', } +export enum ScanPolicy { + NamedExport = 'named_export', + DefaultExport = 'default_export', + All = "all", +} + +export const ARTUS_EXCEPTION_DEFAULT_LOCALE = 'en'; + +export const ARTUS_SERVER_ENV = 'ARTUS_SERVER_ENV'; + export const HOOK_NAME_META_PREFIX = 'hookName:'; export const HOOK_FILE_LOADER = 'appHook:fileLoader'; export const HOOK_CONFIG_HANDLE = 'appHook:configHandle::'; diff --git a/src/loader/factory.ts b/src/loader/factory.ts index 995d217..ccb744e 100644 --- a/src/loader/factory.ts +++ b/src/loader/factory.ts @@ -1,6 +1,6 @@ import * as path from 'path'; import { isInjectable, Container } from '@artus/injection'; -import { ArtusInjectEnum, DEFAULT_LOADER, HOOK_FILE_LOADER, LOADER_NAME_META } from '../constant'; +import { ArtusInjectEnum, DEFAULT_LOADER, HOOK_FILE_LOADER, LOADER_NAME_META, ScanPolicy } from '../constant'; import { Manifest, ManifestItem, @@ -92,8 +92,9 @@ export class LoaderFactory { return loader.load(item); } - async findLoader(opts: LoaderFindOptions): Promise { - const loaderName = await this.findLoaderName(opts); + async findLoader(opts: LoaderFindOptions): Promise { + const { loader: loaderName, exportNames } = await this.findLoaderName(opts); + if (!loaderName) { return null; } @@ -104,6 +105,7 @@ export class LoaderFactory { } const result: LoaderFindResult = { loaderName, + loaderState: { exportNames }, }; if (loaderClazz.onFind) { result.loaderState = await loaderClazz.onFind(opts); @@ -111,33 +113,55 @@ export class LoaderFactory { return result; } - async findLoaderName(opts: LoaderFindOptions): Promise { + async findLoaderName(opts: LoaderFindOptions): Promise<{ loader: string | null, exportNames: string[] }> { for (const [loaderName, LoaderClazz] of LoaderFactory.loaderClazzMap.entries()) { if (await LoaderClazz.is?.(opts)) { - return loaderName; + return { loader: loaderName, exportNames: [] }; } } - const { root, filename } = opts; + const { root, filename, policy = ScanPolicy.All } = opts; // require file for find loader - const targetClazz = await compatibleRequire(path.join(root, filename)); - if (!isClass(targetClazz)) { - // The file is not export with default class - return null; - } + const allExport = await compatibleRequire(path.join(root, filename), true); + const exportNames: string[] = []; + + let loaders = Object.entries(allExport) + .map(([name, targetClazz]) => { + if (!isClass(targetClazz)) { + // The file is not export with default class + return null; + } - // get loader from reflect metadata - const loaderMd = Reflect.getMetadata(HOOK_FILE_LOADER, targetClazz); - if (loaderMd?.loader) { - return loaderMd.loader; - } + if (policy === ScanPolicy.NamedExport && name === 'default') { + return null; + } + + if (policy === ScanPolicy.DefaultExport && name !== 'default') { + return null; + } + + // get loader from reflect metadata + const loaderMd = Reflect.getMetadata(HOOK_FILE_LOADER, targetClazz); + if (loaderMd?.loader) { + exportNames.push(name); + return loaderMd.loader; + } + + // default loder with @Injectable + const injectableMd = isInjectable(targetClazz); + if (injectableMd) { + exportNames.push(name); + return DEFAULT_LOADER; + } + }) + .filter(v => v); + + loaders = Array.from(new Set(loaders)); - // default loder with @Injectable - const injectableMd = isInjectable(targetClazz); - if (injectableMd) { - return DEFAULT_LOADER; + if (loaders.length > 1) { + throw new Error(`Not support multiple loaders for ${path.join(root, filename)}`); } - return null; + return { loader: loaders[0] ?? null, exportNames }; } } diff --git a/src/loader/impl/module.ts b/src/loader/impl/module.ts index f61ba32..ba2e989 100644 --- a/src/loader/impl/module.ts +++ b/src/loader/impl/module.ts @@ -1,4 +1,4 @@ -import { Container, InjectableDefinition, ScopeEnum } from '@artus/injection'; +import { Constructable, Container, InjectableDefinition, ScopeEnum } from '@artus/injection'; import { DefineLoader } from '../decorator'; import { ManifestItem, Loader } from '../types'; import compatibleRequire from '../../utils/compatible_require'; @@ -12,23 +12,34 @@ class ModuleLoader implements Loader { this.container = container; } - async load(item: ManifestItem) { - const moduleClazz = await compatibleRequire(item.path); - const opts: Partial = { - path: item.path, - type: moduleClazz, - scope: ScopeEnum.EXECUTION, // The class used with @artus/core will have default scope EXECUTION, can be overwritten by Injectable decorator - }; - if (item.id) { - opts.id = item.id; - } + async load(item: ManifestItem): Promise { + const origin = await compatibleRequire(item.path, true); + item._loaderState = Object.assign({ exportNames: ['default'] }, item._loaderState); + const { _loaderState: state } = item as { _loaderState: { exportNames: string[] } }; + + const modules: Constructable[] = []; + + for (const name of state.exportNames) { + const moduleClazz = origin[name]; + const opts: Partial = { + path: item.path, + type: moduleClazz, + scope: ScopeEnum.EXECUTION, // The class used with @artus/core will have default scope EXECUTION, can be overwritten by Injectable decorator + }; + if (item.id) { + opts.id = item.id; + } - const shouldOverwriteValue = Reflect.getMetadata(SHOULD_OVERWRITE_VALUE, moduleClazz); + const shouldOverwriteValue = Reflect.getMetadata(SHOULD_OVERWRITE_VALUE, moduleClazz); - if (shouldOverwriteValue || !this.container.hasValue(opts)) { - this.container.set(opts); + if (shouldOverwriteValue || !this.container.hasValue(opts)) { + this.container.set(opts); + } + + modules.push(moduleClazz); } - return moduleClazz; + + return modules; } } diff --git a/src/loader/types.ts b/src/loader/types.ts index 4a6dd43..5e1ddc2 100644 --- a/src/loader/types.ts +++ b/src/loader/types.ts @@ -1,4 +1,5 @@ import { Container } from '@artus/injection'; +import { ScanPolicy } from '../constant'; interface Manifest { items: ManifestItem[]; @@ -20,6 +21,7 @@ interface LoaderFindOptions { root: string; baseDir: string; configDir: string; + policy?: ScanPolicy; } interface LoaderFindResult { diff --git a/src/scanner/scan.ts b/src/scanner/scan.ts index 51567f0..a6af857 100644 --- a/src/scanner/scan.ts +++ b/src/scanner/scan.ts @@ -10,6 +10,7 @@ import { DEFAULT_EXCLUDES, DEFAULT_LOADER_LIST_WITH_ORDER, LOADER_NAME_META, + ScanPolicy, } from '../constant'; import { LoaderFactory, Manifest, ManifestItem } from '../loader'; import { ScannerOptions, WalkOptions } from './types'; @@ -37,6 +38,7 @@ export class Scanner { useRelativePath: true, configDir: DEFAULT_CONFIG_DIR, loaderListGenerator: (defaultLoaderList: string[]) => defaultLoaderList, + policy: ScanPolicy.All, ...options, exclude: DEFAULT_EXCLUDES.concat(options.exclude ?? []), extensions: [...new Set(this.moduleExtensions.concat(options.extensions ?? []))], @@ -169,11 +171,12 @@ export class Scanner { if (ScanUtils.isExclude(filename, extname, this.options.exclude, this.options.extensions)) { return null; } - let loader = await loaderFactory.findLoaderName({ + let { loader } = await loaderFactory.findLoaderName({ filename, baseDir, root, configDir, + policy: this.options.policy, }); if (loader === 'framework-config') { // SEEME: framework-config is a special loader, cannot be used when scan, need refactor later @@ -242,6 +245,7 @@ export class Scanner { extensions: this.options.extensions, exclude: this.options.exclude, configDir: this.options.configDir, + policy: this.options.policy, }; if (source === 'plugin') { diff --git a/src/scanner/types.ts b/src/scanner/types.ts index dcc0dbf..6cc1792 100644 --- a/src/scanner/types.ts +++ b/src/scanner/types.ts @@ -2,6 +2,7 @@ import { BaseLoader, ManifestItem } from "../loader"; import { FrameworkConfig } from "../framework"; import { PluginConfigItem } from "../plugin/types"; import { Application } from "../types"; +import { ScanPolicy } from "../constant"; export interface ScannerOptions { appName: string; @@ -10,6 +11,7 @@ export interface ScannerOptions { useRelativePath: boolean; exclude: string[]; configDir: string; + policy: ScanPolicy; envs?: string[]; framework?: FrameworkConfig; plugin?: Record>; @@ -21,6 +23,7 @@ export interface WalkOptions { source: string; baseDir: string; configDir: string; + policy: ScanPolicy; extensions: string[]; exclude: string[]; itemMap: Map; diff --git a/src/scanner/utils.ts b/src/scanner/utils.ts index e957c53..bd97463 100644 --- a/src/scanner/utils.ts +++ b/src/scanner/utils.ts @@ -57,6 +57,7 @@ export class ScanUtils { root, baseDir, configDir, + policy: options.policy, }); if (!loaderFindResult) { continue; diff --git a/src/utils/compatible_require.ts b/src/utils/compatible_require.ts index ec72f2e..87960f3 100644 --- a/src/utils/compatible_require.ts +++ b/src/utils/compatible_require.ts @@ -4,10 +4,10 @@ import assert from 'assert'; * compatible esModule require * @param path */ -export default async function compatibleRequire(path: string): Promise { +export default async function compatibleRequire(path: string, origin = false): Promise { const requiredModule = await import(path); assert(requiredModule, `module '${path}' exports is undefined`); - return requiredModule.default || requiredModule; + return origin ? requiredModule : (requiredModule.default || requiredModule); } \ No newline at end of file diff --git a/test/fixtures/app_koa_with_ts/src/koa_app.ts b/test/fixtures/app_koa_with_ts/src/koa_app.ts index 1640fdc..5ddbf99 100644 --- a/test/fixtures/app_koa_with_ts/src/koa_app.ts +++ b/test/fixtures/app_koa_with_ts/src/koa_app.ts @@ -1,5 +1,7 @@ -import { Injectable } from '@artus/injection'; +import { Injectable, ScopeEnum } from '@artus/injection'; import Koa from 'koa'; -@Injectable() -export default class KoaApplication extends Koa {} +@Injectable({ + scope: ScopeEnum.SINGLETON, +}) +export default class KoaApplication extends Koa { } diff --git a/test/fixtures/app_with_lifecycle/lifecyclelist.ts b/test/fixtures/app_with_lifecycle/lifecyclelist.ts index 4eb2e18..7647701 100644 --- a/test/fixtures/app_with_lifecycle/lifecyclelist.ts +++ b/test/fixtures/app_with_lifecycle/lifecyclelist.ts @@ -1,6 +1,8 @@ -import { Injectable } from '../../../src'; +import { Injectable, ScopeEnum } from '../../../src'; -@Injectable() +@Injectable({ + scope: ScopeEnum.SINGLETON, +}) export default class LifecycleList { lifecycleList: string[] = []; diff --git a/test/fixtures/application_specific/src/index.ts b/test/fixtures/application_specific/src/index.ts index 49b0aea..57b6992 100644 --- a/test/fixtures/application_specific/src/index.ts +++ b/test/fixtures/application_specific/src/index.ts @@ -1,9 +1,11 @@ import path from 'path'; import { Manifest, ArtusApplication, ArtusInjectEnum } from "../../../../src"; import { AbstractBar } from '../../frameworks/bar/src'; -import { Inject, Injectable } from "@artus/injection"; +import { Inject, Injectable, ScopeEnum } from "@artus/injection"; -@Injectable() +@Injectable({ + scope: ScopeEnum.SINGLETON, +}) export default class MyArtusApplication { @Inject('ABSTRACT_BAR') private bar: AbstractBar; diff --git a/test/fixtures/application_specific/src/plugins/artus_plugin_mysql_ob/src/client.ts b/test/fixtures/application_specific/src/plugins/artus_plugin_mysql_ob/src/client.ts index bddcea5..cd43ce4 100644 --- a/test/fixtures/application_specific/src/plugins/artus_plugin_mysql_ob/src/client.ts +++ b/test/fixtures/application_specific/src/plugins/artus_plugin_mysql_ob/src/client.ts @@ -1,4 +1,4 @@ -import { Injectable } from "@artus/injection"; +import { Injectable, ScopeEnum } from "@artus/injection"; export interface MysqlConfig { clientName: string @@ -6,6 +6,7 @@ export interface MysqlConfig { @Injectable({ id: 'ARTUS_MYSQL', + scope: ScopeEnum.SINGLETON, }) export default class Client { private clientName = ''; diff --git a/test/fixtures/application_specific/src/plugins/artus_plugin_mysql_rds/src/client.ts b/test/fixtures/application_specific/src/plugins/artus_plugin_mysql_rds/src/client.ts index bddcea5..cd43ce4 100644 --- a/test/fixtures/application_specific/src/plugins/artus_plugin_mysql_rds/src/client.ts +++ b/test/fixtures/application_specific/src/plugins/artus_plugin_mysql_rds/src/client.ts @@ -1,4 +1,4 @@ -import { Injectable } from "@artus/injection"; +import { Injectable, ScopeEnum } from "@artus/injection"; export interface MysqlConfig { clientName: string @@ -6,6 +6,7 @@ export interface MysqlConfig { @Injectable({ id: 'ARTUS_MYSQL', + scope: ScopeEnum.SINGLETON, }) export default class Client { private clientName = ''; diff --git a/test/fixtures/application_specific/src/plugins/artus_plugin_redis/src/client.ts b/test/fixtures/application_specific/src/plugins/artus_plugin_redis/src/client.ts index 9d73ff5..6d4a108 100644 --- a/test/fixtures/application_specific/src/plugins/artus_plugin_redis/src/client.ts +++ b/test/fixtures/application_specific/src/plugins/artus_plugin_redis/src/client.ts @@ -1,4 +1,4 @@ -import { Injectable } from "@artus/injection"; +import { Injectable, ScopeEnum } from "@artus/injection"; export interface RedisConfig { clientName: string @@ -6,6 +6,7 @@ export interface RedisConfig { @Injectable({ id: 'ARTUS_REDIS', + scope: ScopeEnum.SINGLETON, }) export default class Client { private clientName = ''; diff --git a/test/fixtures/artus_application/src/index.ts b/test/fixtures/artus_application/src/index.ts index 49b0aea..57b6992 100644 --- a/test/fixtures/artus_application/src/index.ts +++ b/test/fixtures/artus_application/src/index.ts @@ -1,9 +1,11 @@ import path from 'path'; import { Manifest, ArtusApplication, ArtusInjectEnum } from "../../../../src"; import { AbstractBar } from '../../frameworks/bar/src'; -import { Inject, Injectable } from "@artus/injection"; +import { Inject, Injectable, ScopeEnum } from "@artus/injection"; -@Injectable() +@Injectable({ + scope: ScopeEnum.SINGLETON, +}) export default class MyArtusApplication { @Inject('ABSTRACT_BAR') private bar: AbstractBar; diff --git a/test/fixtures/artus_application/src/plugins/artus_plugin_mysql_ob/src/client.ts b/test/fixtures/artus_application/src/plugins/artus_plugin_mysql_ob/src/client.ts index bddcea5..cd43ce4 100644 --- a/test/fixtures/artus_application/src/plugins/artus_plugin_mysql_ob/src/client.ts +++ b/test/fixtures/artus_application/src/plugins/artus_plugin_mysql_ob/src/client.ts @@ -1,4 +1,4 @@ -import { Injectable } from "@artus/injection"; +import { Injectable, ScopeEnum } from "@artus/injection"; export interface MysqlConfig { clientName: string @@ -6,6 +6,7 @@ export interface MysqlConfig { @Injectable({ id: 'ARTUS_MYSQL', + scope: ScopeEnum.SINGLETON, }) export default class Client { private clientName = ''; diff --git a/test/fixtures/artus_application/src/plugins/artus_plugin_mysql_rds/src/client.ts b/test/fixtures/artus_application/src/plugins/artus_plugin_mysql_rds/src/client.ts index bddcea5..cd43ce4 100644 --- a/test/fixtures/artus_application/src/plugins/artus_plugin_mysql_rds/src/client.ts +++ b/test/fixtures/artus_application/src/plugins/artus_plugin_mysql_rds/src/client.ts @@ -1,4 +1,4 @@ -import { Injectable } from "@artus/injection"; +import { Injectable, ScopeEnum } from "@artus/injection"; export interface MysqlConfig { clientName: string @@ -6,6 +6,7 @@ export interface MysqlConfig { @Injectable({ id: 'ARTUS_MYSQL', + scope: ScopeEnum.SINGLETON, }) export default class Client { private clientName = ''; diff --git a/test/fixtures/artus_application/src/plugins/artus_plugin_redis/src/client.ts b/test/fixtures/artus_application/src/plugins/artus_plugin_redis/src/client.ts index 9d73ff5..b381d71 100644 --- a/test/fixtures/artus_application/src/plugins/artus_plugin_redis/src/client.ts +++ b/test/fixtures/artus_application/src/plugins/artus_plugin_redis/src/client.ts @@ -1,11 +1,12 @@ -import { Injectable } from "@artus/injection"; +import { Injectable, ScopeEnum } from "@artus/injection"; export interface RedisConfig { - clientName: string + clientName: string, } @Injectable({ id: 'ARTUS_REDIS', + scope: ScopeEnum.SINGLETON, }) export default class Client { private clientName = ''; diff --git a/test/fixtures/custom_instance/custom.ts b/test/fixtures/custom_instance/custom.ts index 03cee03..ae616a6 100644 --- a/test/fixtures/custom_instance/custom.ts +++ b/test/fixtures/custom_instance/custom.ts @@ -1,6 +1,8 @@ -import { Injectable } from "../../../src/index"; +import { Injectable, ScopeEnum } from "../../../src/index"; -@Injectable() +@Injectable({ + scope: ScopeEnum.SINGLETON, +}) export default class Custom { private name: string; diff --git a/test/fixtures/frameworks/bar/src/index.ts b/test/fixtures/frameworks/bar/src/index.ts index 04d6024..0e5b9e2 100644 --- a/test/fixtures/frameworks/bar/src/index.ts +++ b/test/fixtures/frameworks/bar/src/index.ts @@ -1,10 +1,13 @@ -import { Inject, Injectable } from "@artus/injection"; +import { Inject, Injectable, ScopeEnum } from "@artus/injection"; import { AbstractFoo } from "../../abstract/foo"; export interface AbstractBar extends AbstractFoo { } -@Injectable({ id: 'ABSTRACT_BAR' }) -export default class FrameworkBar implements AbstractBar { +@Injectable({ + id: 'ABSTRACT_BAR', + scope: ScopeEnum.SINGLETON, +}) +export class FrameworkBar implements AbstractBar { @Inject('ABSTRACT_FOO') private foo: AbstractFoo; diff --git a/test/fixtures/frameworks/layer/foo/foo1/src/index.ts b/test/fixtures/frameworks/layer/foo/foo1/src/index.ts index 827abb3..b620bfc 100644 --- a/test/fixtures/frameworks/layer/foo/foo1/src/index.ts +++ b/test/fixtures/frameworks/layer/foo/foo1/src/index.ts @@ -1,9 +1,12 @@ -import { Injectable } from "@artus/injection"; +import { Injectable, ScopeEnum } from "@artus/injection"; import { ArtusApplication } from '../../../../../../../src'; import { server } from './lifecycle'; -@Injectable({ id: 'ABSTRACT_FOO' }) -export default class FrameworkFoo extends ArtusApplication { +@Injectable({ + id: 'ABSTRACT_FOO', + scope: ScopeEnum.SINGLETON, +}) +export class FrameworkFoo extends ArtusApplication { isListening(): boolean { return server?.listening; } diff --git a/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_hbase/src/client.ts b/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_hbase/src/client.ts index 96ec9f5..34f7818 100644 --- a/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_hbase/src/client.ts +++ b/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_hbase/src/client.ts @@ -1,4 +1,4 @@ -import { Injectable } from "@artus/injection"; +import { Injectable, ScopeEnum } from "@artus/injection"; export interface MysqlConfig { clientName: string @@ -6,6 +6,7 @@ export interface MysqlConfig { @Injectable({ id: 'ARTUS_HBASE', + scope: ScopeEnum.SINGLETON, }) export default class Client { private clientName = ''; diff --git a/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_mysql_rds/src/client.ts b/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_mysql_rds/src/client.ts index bddcea5..cd43ce4 100644 --- a/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_mysql_rds/src/client.ts +++ b/test/fixtures/frameworks/layer/foo/foo2/node_modules/artus_plugin_mysql_rds/src/client.ts @@ -1,4 +1,4 @@ -import { Injectable } from "@artus/injection"; +import { Injectable, ScopeEnum } from "@artus/injection"; export interface MysqlConfig { clientName: string @@ -6,6 +6,7 @@ export interface MysqlConfig { @Injectable({ id: 'ARTUS_MYSQL', + scope: ScopeEnum.SINGLETON, }) export default class Client { private clientName = ''; diff --git a/test/fixtures/frameworks/layer/foo/foo2/src/index.ts b/test/fixtures/frameworks/layer/foo/foo2/src/index.ts index 827abb3..b620bfc 100644 --- a/test/fixtures/frameworks/layer/foo/foo2/src/index.ts +++ b/test/fixtures/frameworks/layer/foo/foo2/src/index.ts @@ -1,9 +1,12 @@ -import { Injectable } from "@artus/injection"; +import { Injectable, ScopeEnum } from "@artus/injection"; import { ArtusApplication } from '../../../../../../../src'; import { server } from './lifecycle'; -@Injectable({ id: 'ABSTRACT_FOO' }) -export default class FrameworkFoo extends ArtusApplication { +@Injectable({ + id: 'ABSTRACT_FOO', + scope: ScopeEnum.SINGLETON, +}) +export class FrameworkFoo extends ArtusApplication { isListening(): boolean { return server?.listening; } diff --git a/test/fixtures/logger/src/test_clazz.ts b/test/fixtures/logger/src/test_clazz.ts index 81b05fb..e96e594 100644 --- a/test/fixtures/logger/src/test_clazz.ts +++ b/test/fixtures/logger/src/test_clazz.ts @@ -1,12 +1,14 @@ -import { Inject, Injectable } from '@artus/injection'; +import { Inject, Injectable, ScopeEnum } from '@artus/injection'; import { ArtusLogger, LoggerLevel } from '../../../../src/logger'; -@Injectable() +@Injectable({ + scope: ScopeEnum.SINGLETON, +}) export default class TestLoggerClazz { @Inject() private logger!: ArtusLogger; - public testLog(level: LoggerLevel, message: string|Error, ...splat: any[]) { + public testLog(level: LoggerLevel, message: string | Error, ...splat: any[]) { this.logger.log({ level, message, @@ -30,7 +32,7 @@ export default class TestLoggerClazz { this.logger.warn(message, ...args); } - public testError(message: string|Error, ...args: any[]) { + public testError(message: string | Error, ...args: any[]) { this.logger.error(message, ...args); } } diff --git a/test/fixtures/logger/src/test_custom_clazz.ts b/test/fixtures/logger/src/test_custom_clazz.ts index 3a72218..87b4312 100644 --- a/test/fixtures/logger/src/test_custom_clazz.ts +++ b/test/fixtures/logger/src/test_custom_clazz.ts @@ -1,7 +1,9 @@ -import { Inject, Injectable } from '@artus/injection'; +import { Inject, Injectable, ScopeEnum } from '@artus/injection'; import CustomLogger from './custom_logger'; -@Injectable() +@Injectable({ + scope: ScopeEnum.SINGLETON, +}) export default class TestCustomLoggerClazz { @Inject() private logger!: CustomLogger; @@ -10,7 +12,7 @@ export default class TestCustomLoggerClazz { this.logger.info(message, ...args); } - public testError(message: string|Error, ...args: any[]) { + public testError(message: string | Error, ...args: any[]) { this.logger.error(message, ...args); } } diff --git a/test/fixtures/named_export/package.json b/test/fixtures/named_export/package.json new file mode 100644 index 0000000..17fd808 --- /dev/null +++ b/test/fixtures/named_export/package.json @@ -0,0 +1,3 @@ +{ + "name": "named-export" +} \ No newline at end of file diff --git a/test/fixtures/named_export/src/config/config.default.ts b/test/fixtures/named_export/src/config/config.default.ts new file mode 100644 index 0000000..a89c969 --- /dev/null +++ b/test/fixtures/named_export/src/config/config.default.ts @@ -0,0 +1,3 @@ +export default { + key: 'random', +}; \ No newline at end of file diff --git a/test/fixtures/named_export/src/index.ts b/test/fixtures/named_export/src/index.ts new file mode 100644 index 0000000..9d814eb --- /dev/null +++ b/test/fixtures/named_export/src/index.ts @@ -0,0 +1,5 @@ +export * from './mysql'; + +import Redis from './redis'; + +export { Redis }; \ No newline at end of file diff --git a/test/fixtures/named_export/src/mysql.ts b/test/fixtures/named_export/src/mysql.ts new file mode 100644 index 0000000..821a2a8 --- /dev/null +++ b/test/fixtures/named_export/src/mysql.ts @@ -0,0 +1,25 @@ +import { Injectable, ScopeEnum } from "../../../../src"; + +@Injectable({ + scope: ScopeEnum.SINGLETON, +}) +export class Mysql { + private name = 'mysql'; + + getName() { + return this.name; + } +} + +export const number = 1; + +export const object = { a: 1 }; + + +export class Mysql2 { + private name = 'mysql2'; + + getName() { + return this.name; + } +} \ No newline at end of file diff --git a/test/fixtures/named_export/src/redis.ts b/test/fixtures/named_export/src/redis.ts new file mode 100644 index 0000000..3e0760c --- /dev/null +++ b/test/fixtures/named_export/src/redis.ts @@ -0,0 +1,23 @@ +import { Injectable, ScopeEnum } from "../../../../src"; + +@Injectable({ + scope: ScopeEnum.SINGLETON, +}) +export default class Redis { + private name = 'redis'; + + getName() { + return this.name; + } +} + +@Injectable() +export class Redis2 { + private name = 'redis2'; + + getName() { + return this.name; + } +} + +export { Redis }; \ No newline at end of file diff --git a/test/loader.test.ts b/test/loader.test.ts index db77cdd..040ded2 100644 --- a/test/loader.test.ts +++ b/test/loader.test.ts @@ -51,7 +51,7 @@ describe('test/loader.test.ts', () => { const container = new Container('testDefault'); const loaderFactory = LoaderFactory.create(container); - const loaderName = await loaderFactory.findLoaderName({ + const { loader: loaderName } = await loaderFactory.findLoaderName({ filename: 'test_clazz.ts', root: path.resolve(__dirname, './fixtures/module_with_custom_loader/src'), baseDir: path.resolve(__dirname, './fixtures/module_with_custom_loader/src'), diff --git a/test/scanner.test.ts b/test/scanner.test.ts index 96f80da..5204fdb 100644 --- a/test/scanner.test.ts +++ b/test/scanner.test.ts @@ -1,6 +1,7 @@ +import 'reflect-metadata'; import { Scanner } from '../src/scanner'; import path from 'path'; -import { LoaderFactory } from '../src'; +import { ScanPolicy , LoaderFactory } from '../src'; describe('test/scanner.test.ts', () => { @@ -58,4 +59,28 @@ describe('test/scanner.test.ts', () => { expect(manifest.items.length).toBe(1); expect(manifest.items[0]?.loader).toBe('test-custom-loader'); }); + + it('should scan application with all injectable class', async () => { + const scanner = new Scanner({ needWriteFile: false, extensions: ['.ts', '.js', '.json'] }); + const scanResults = await scanner.scan(path.resolve(__dirname, './fixtures/named_export')); + const { default: manifest } = scanResults; + expect(manifest.items).toBeDefined(); + expect(manifest.items.length).toBe(5); + }); + + it('should scan application with named export class', async () => { + const scanner = new Scanner({ needWriteFile: false, extensions: ['.ts', '.js', '.json'], policy: ScanPolicy.NamedExport }); + const scanResults = await scanner.scan(path.resolve(__dirname, './fixtures/named_export')); + const { default: manifest } = scanResults; + expect(manifest.items).toBeDefined(); + expect(manifest.items.length).toBe(5); + }); + + it('should scan application with default export class', async () => { + const scanner = new Scanner({ needWriteFile: false, extensions: ['.ts', '.js', '.json'], policy: ScanPolicy.DefaultExport }); + const scanResults = await scanner.scan(path.resolve(__dirname, './fixtures/named_export')); + const { default: manifest } = scanResults; + expect(manifest.items).toBeDefined(); + expect(manifest.items.length).toBe(3); + }); });