Skip to content

Commit

Permalink
feat(loader): support filter non-injectable and non-default file (#153)
Browse files Browse the repository at this point in the history
* feat(loader): support filter non-default export file and the class not injectable

* feat(loader): cover more case

* feat(scanner): ignore all file without extname

* feat: bump @artus/injection to v0.4.0

* feat(loader): use isClass instead default select
  • Loading branch information
noahziheng authored Aug 1, 2022
1 parent a0acead commit 6945a13
Show file tree
Hide file tree
Showing 8 changed files with 45 additions and 18 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
"typescript": "^4.7.2"
},
"dependencies": {
"@artus/injection": "^0.3.1",
"@artus/injection": "^0.4.0",
"@artus/pipeline": "^0.2.2",
"deepmerge": "^4.2.2",
"minimatch": "^5.0.1"
Expand Down
34 changes: 25 additions & 9 deletions src/loader/factory.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as path from 'path';
import { Container } from '@artus/injection';
import { isInjectable, Container } from '@artus/injection';
import { ArtusInjectEnum, DEFAULT_LOADER, HOOK_FILE_LOADER, LOADER_NAME_META } from '../constant';
import {
Manifest,
Expand All @@ -13,6 +13,7 @@ import ConfigurationHandler from '../configuration';
import { LifecycleManager } from '../lifecycle';
import compatibleRequire from '../utils/compatible_require';
import LoaderEventEmitter, { LoaderEventListener } from './loader_event';
import { isClass } from '../utils/is';

export class LoaderFactory {
private container: Container;
Expand Down Expand Up @@ -91,8 +92,12 @@ export class LoaderFactory {
return loader.load(item);
}

async findLoader(opts: LoaderFindOptions): Promise<LoaderFindResult> {
async findLoader(opts: LoaderFindOptions): Promise<LoaderFindResult|null> {
const loaderName = await this.findLoaderName(opts);
if (!loaderName) {
return null;
}

const loaderClazz = LoaderFactory.loaderClazzMap.get(loaderName);
if (!loaderClazz) {
throw new Error(`Cannot find loader '${loaderName}'`);
Expand All @@ -106,22 +111,33 @@ export class LoaderFactory {
return result;
}

async findLoaderName(opts: LoaderFindOptions): Promise<string> {
async findLoaderName(opts: LoaderFindOptions): Promise<string|null> {
for (const [loaderName, LoaderClazz] of LoaderFactory.loaderClazzMap.entries()) {
if (await LoaderClazz.is?.(opts)) {
return loaderName;
}
}
const { root, filename } = 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;
}

// get loader from reflect metadata
const target = await compatibleRequire(path.join(root, filename));
const metadata = Reflect.getMetadata(HOOK_FILE_LOADER, target);
if (metadata?.loader) {
return metadata.loader;
const loaderMd = Reflect.getMetadata(HOOK_FILE_LOADER, targetClazz);
if (loaderMd?.loader) {
return loaderMd.loader;
}

// default loder with @Injectable
const injectableMd = isInjectable(targetClazz);
if (injectableMd) {
return DEFAULT_LOADER;
}

// default loder
return DEFAULT_LOADER;
return null;
}
}
13 changes: 9 additions & 4 deletions src/scanner/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,22 @@ export class ScanUtils {
}

if (itemStat.isFile()) {
if (!extname) {
// Exclude file without extname
continue;
}
const filename = path.basename(realPath);
const filenameWithoutExt = path.basename(realPath, extname);
const {
loaderName,
loaderState,
} = await ScanUtils.loaderFactory.findLoader({
const loaderFindResult = await ScanUtils.loaderFactory.findLoader({
filename,
root,
baseDir,
configDir,
});
if (!loaderFindResult) {
continue;
}
const { loaderName, loaderState } = loaderFindResult;
const item: ManifestItem = {
path: options.extensions.includes(extname) ? path.resolve(root, filenameWithoutExt) : realPath,
extname,
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/app_koa_with_ts/src/no_ext_file
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
hello:world
1 change: 1 addition & 0 deletions test/fixtures/app_koa_with_ts/src/services/no_default.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export class Clazz {}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default class Clazz {}
3 changes: 3 additions & 0 deletions test/fixtures/frameworks/bar/src/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ export function HttpController(options?: ControllerParams): ClassDecorator {
const prefix = options?.path ?? '';
return (target: any) => {
controllerMap.add({ prefix, clazz: target });
Injectable({
scope: ScopeEnum.EXECUTION,
})(target);
};
}

Expand Down
8 changes: 4 additions & 4 deletions test/scanner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ describe('test/scanner.test.ts', () => {
expect(manifest).toBeDefined();
expect(manifest.items).toBeDefined();
// console.log('manifest', manifest);
expect(manifest.items.length).toBe(11);
expect(manifest.items.length).toBe(10);

expect(manifest.items.find(item => item.filename === 'not_to_be_scanned_file.ts')).toBeFalsy();

Expand All @@ -21,17 +21,17 @@ describe('test/scanner.test.ts', () => {
expect(manifest.items.filter(item => item.loader === 'exception').length).toBe(1);
expect(manifest.items.filter(item => item.loader === 'lifecycle-hook-unit').length).toBe(2);
expect(manifest.items.filter(item => item.loader === 'config').length).toBe(1);
expect(manifest.items.filter(item => item.loader === 'module').length).toBe(5);
expect(manifest.items.filter(item => item.loader === 'module').length).toBe(4);

expect(manifest.items.filter(item => item.unitName === 'redis').length).toBe(2);
expect(manifest.items.filter(item => item.unitName === 'mysql').length).toBe(0);
expect(manifest.items.filter(item => item.source === 'app').length).toBe(9);
expect(manifest.items.filter(item => item.source === 'app').length).toBe(8);

const { dev: devManifest } = scanResults;
// console.log('devManifest', devManifest);
expect(devManifest).toBeDefined();
expect(devManifest.items).toBeDefined();
expect(devManifest.items.length).toBe(13);
expect(devManifest.items.length).toBe(12);
expect(devManifest.items.filter(item => item.loader === 'config').length).toBe(2);
expect(devManifest.items.filter(item => item.loader === 'plugin-meta').length).toBe(2);
expect(devManifest.items.find(item => item.unitName === 'testDuplicate')).toBeDefined();
Expand Down

0 comments on commit 6945a13

Please sign in to comment.