npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@typeix/modules

v8.8.0

Published

missing modularity system for nodejs

Downloads

293

Readme

@typeix/modules

Build Status Coverage Status npm

Modules

Package provides Modules API with Dependency Injection, A module is a class annotated with a @Module() decorator. The @Module() decorator provides metadata information to ModuleInjector, that makes use of to organize application module dependency graph.

Tree Traversal Injector uses deep-tree left traversal algorithm to create application module instances, that means that deepest three objects are created first.

Objects would be created in order A -> C -> E -> D -> B -> H -> I -> G -> F if we illustrate that would look like:

       A       H
     /   \     |
    C     E    I
     \   /     |
       D       G
       |      /
       B     /
        \   /
          F

You can easily extend application module decorator to provide custom metadata API in own projects, due to large application graph application modules should be initialized once on application start or bootstrap time.

Installing:

npm i @typeix/modules @typeix/di --save
npm i @types/node typescript --save-dev

Decorators

@Module() decorator contains metadata information of import modules, export providers and providers to be created. imports - can only contain modules or module imports exports - providers to be exported which are created or imported at module creation providers - list of providers that are created at module creation

export interface IModuleMetadata {
  imports?: Array<Function | IProvider>;
  exports?: Array<Function | IProvider>;
  providers: Array<Function | IProvider>;
}

Extending module decorator in custom projects can be done as following:

import {Module as AModule, IModuleMetadata as AIModuleMetadata} from "@typeix/modules";

export interface IModuleMetadata extends AIModuleMetadata {
    controllers?: Array<Function | IProvider>;
    path?: string;
}

export function Module(config: IModuleMetadata): ClassDecorator {
    if (!isArray(config.exports)) {
        config.exports = [];
    }
    return AModule(config);
}

Usage

Once created asynchronously modules can be accessed via ModuleInjector , in example we can see that ApplicationModuleD create providers AService and BService and exports them to other modules, what that means is that same object reference will be provided to ApplicationModuleC or module with imports ApplicationModuleD, however ApplicationModuleB will receive same instance of service BService but AService will be newly created object since is defined as provider in providers: [AService]

import {Module, ModuleInjector} from "@typeix/modules";
import {Injector, Injectable, Inject} from "@typeix/di";

@Injectable
class AService {
}

@Injectable
class BService {
  @Inject() aService: AService;
  doWhatever() {}
}

@Module({
  providers: [AService, BService],
  exports: [AService, BService]
})
class ApplicationModuleD {
  @Inject() bService: BService;
  @Inject() aService: AService;
}

ApplicationModuleC implements ApplicationModuleD and BService, AService are same references exported from ApplicationModuleD.

@Module({
  imports: [ApplicationModuleD],
  exports: [AService, BService],
  providers: []
})
class ApplicationModuleC {
  @Inject() bService: BService;
  @Inject() aService: AService;
}

ApplicationModuleB implements ApplicationModuleC and BService is same reference however AService is new instance of AService class, because it's provided as new provider on ApplicationModuleB.

@Module({
  imports: [ApplicationModuleC],
  providers: [AService]
})
class ApplicationModuleB {
  @Inject() bService: BService;
  @Inject() aService: AService;
}

ModuleInjector

NOTE: By default all providers are immutable, however you can define mutable provider keys. If provider is not mutable, and you are trying to create new instance of same provider on current ModuleInjector instance, injector will throw error.

Async

Since version 8.x default Injector behavior is converted to async API, if you want to use sync api you need to use ModuleInjector.Sync.createAndResolve difference is that Async API supports Async providers, it's allowed to use of async/await in factory and return Promises in value provider!

ModuleInjector.createAndResolve(Class, sharedProviders) special sharedProviders property will create all providers which are provided and visible to all modules, however if module have same provider provided in providers module metadata, new instance will be delivered to that module.

class ModuleInjector {
    static createAndResolve(Class: Function | IProvider, sharedProviders: Array<Function | IProvider>, mutableKeys?: Array<any>): Promise<ModuleInjector>;
    get(Class: Function | IProvider): any;
    getInjector(Class: Function | IProvider): Injector;
    has(Class: IProvider | Function): boolean;
    remove(Class: Function | IProvider): boolean;
    getAllMetadata(): Map<any, IModuleMetadata>;
    createAndResolveSharedProviders(providers: Array<Function | IProvider>): Promise<Injector>;
    createAndResolve(Class: Function | IProvider, mutableKeys?: Array<any>): Promise<Injector>;
}

Once modules are created by ModuleInjector all objects and references can be accessed via API

const injector = await ModuleInjector.createAndResolve(ApplicationModuleB);

Sync API

Sync api is accessible via ModuleInjector.Sync.createAndResolve(Class, sharedProviders) or by simply importing SyncModuleInjector

class SyncModuleInjector {
    static createAndResolve(Class: Function | IProvider, sharedProviders: Array<Function | IProvider>, mutableKeys?: Array<any>): SyncModuleInjector;
    get(Class: Function | IProvider): any;
    getInjector(Class: Function | IProvider): SyncInjector;
    has(Class: IProvider | Function): boolean;
    remove(Class: Function | IProvider): boolean;
    getAllMetadata(): Map<any, IModuleMetadata>;
    createAndResolveSharedProviders(providers: Array<Function | IProvider>): SyncInjector;
    createAndResolve(Class: Function | IProvider, mutableKeys?: Array<any>): SyncInjector;
}

In following example we can see sync api usage:

const injector = ModuleInjector.Sync.createAndResolve(ApplicationModuleB);
const dModule: ApplicationModuleD = injector.get(ApplicationModuleD);
const cModule: ApplicationModuleC = injector.get(ApplicationModuleC);
const bModule: ApplicationModuleB = injector.get(ApplicationModuleB);
bModule.myAction();
const bModuleInjector = injector.getInjector(ApplicationModuleB);
const bService = bModuleInjector.get(BService);
bService.doWhatever();

In example above injected service references are evaluated as true

const dModuleInjector = injector.getInjector(ApplicationModuleD);
const cModuleInjector = injector.getInjector(ApplicationModuleC);
const bModuleInjector = injector.getInjector(ApplicationModuleB);

bModuleInjector.get(BService) === cModuleInjector.get(BService)
bModuleInjector.get(BService) === dModuleInjector.get(BService)

cModuleInjector.get(AService) === dModuleInjector.get(AService)
bModuleInjector.get(AService) != cModuleInjector.get(AService)
bModuleInjector.get(AService) != dModuleInjector.get(AService)