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

@leandromatos/provider-manager

v0.0.0-snapshot.20241014.4

Published

Provider Manager

Downloads

65

Readme

Provider Manager 📦

npm GitHub Workflow Status GitHub Workflow Status Codecov GitHub

Provider Manager is a lightweight dependency injection container designed to manage class constructors and factory functions. It allows you to register and resolve dependencies easily and supports both class-based providers and factory-based providers, giving you flexibility in how you handle your dependencies.

Installation

Install the package using yarn or any other package manager:

yarn add @leandromatos/provider-manager

Features

  • Register providers using class constructors or factory functions.
  • Resolve dependencies using string identifiers or directly via class constructors or factory functions.
  • Automatic dependency resolution with @Inject.
  • Simple and intuitive API for managing dependencies.

Decorators

@Injectable

The @Injectable decorator marks a class or factory function as a provider that can be managed by the ProviderManager. Without this decorator, the ProviderManager will not be able to handle the class or factory.

@Injectable()
class Logger {
  log(message: string): void {
    console.log(`[LOG]: ${message}`)
  }
}

In this example, Logger is marked as @Injectable, which allows it to be registered and resolved by the ProviderManager.

@Inject

The @Inject decorator injects dependencies into the constructor of a class-based provider. It tells ProviderManager what dependencies should be resolved when creating a class instance.

@Injectable()
class UserService {
  constructor(
    @Inject(Logger) private readonly logger: Logger,
    @Inject(ConfigService) private readonly configService: Config
  ) {}
}

In this example, the UserService class depends on Logger and ConfigService. The @Inject decorator ensures that when UserService is resolved, Logger and ConfigService will be automatically injected.

Usage

Here’s a basic example that demonstrates how to use ProviderManager to register and resolve different types of providers.

Example: Basic Setup

import { Inject, Injectable, ProviderManager } from '@leandromatos/provider-manager'

// A factory-based provider
type Config = {
  appName: string
  version: string
}

@Injectable()
const ConfigService = (): Config => ({
  appName: 'MyApp',
  version: '1.0.0',
})

// A class-based provider
@Injectable()
class Logger {
  log(message: string): void {
    console.log(`[LOG]: ${message}`)
  }
}

// A class-based provider
@Injectable()
class DatabaseConnection {
  constructor(private connectionString: string) {}

  connect(): void {
    console.log(`Connected to database: ${this.connectionString}`)
  }
}

// A class-based provider with dependencies
@Injectable()
class UserService {
  constructor(
    @Inject(Logger) private readonly logger: Logger,
    @Inject(ConfigService) private readonly configService: Config
  ) {}

  createUser(name: string): void {
    this.logger.log(`Creating user: ${name} for ${this.configService.appName}`)
  }
}

// Initialize the ProviderManager
const providerManager = new ProviderManager()

Registering Providers

You can register providers using constructors, factories, or string identifiers. Below, we'll demonstrate registering various types of providers:

Class-based Provider

A class-based provider is a simple class that can be instantiated by the ProviderManager.

@Injectable()
class Logger {
  log(message: string): void {
    console.log(`[LOG]: ${message}`)
  }
}

// Register a class-based provider
providerManager.registerProvider(Logger)

Factory-based Provider with String Identifier

A factory-based provider is a function that returns an instance of a class or object. You can assign a custom string identifier for later retrieval when using a factory.

@Injectable()
class DatabaseConnection {
  constructor(private connectionString: string) {}

  connect(): void {
    console.log(`Connected to database: ${this.connectionString}`)
  }
}

// Register a factory-based provider with a string identifier
providerManager.registerProvider(() => new DatabaseConnection('postgresql://main-database:5432'), 'MAIN_DATABASE')

Factory-based Provider without Identifier

You can also register a factory-based provider without using an identifier. In this case, the function itself acts as the identifier.

type Config = {
  appName: string
  version: string
}

@Injectable()
const ConfigService = (): Config => ({
  appName: 'MyApp',
  version: '1.0.0',
})

// Register a factory-based provider without an identifier
providerManager.registerProvider(ConfigService)

Class-based Provider with Dependencies

When you have a class-based provider that depends on other providers, you can use the @Inject decorator to inject these dependencies.

@Injectable()
class UserService {
  constructor(
    @Inject(Logger) private readonly logger: Logger,
    @Inject(ConfigService) private readonly configService: Config
  ) {}

  createUser(name: string): void {
    this.logger.log(`Creating user: ${name} for ${this.configService.appName}`)
  }
}

// Register a class-based provider with dependencies
providerManager
  .registerProvider(Logger)
  .registerProvider(ConfigService)
  .registerProvider(UserService)

Resolving Providers

Once the providers are registered, you can resolve them through the ProviderManager using either their constructor, factory, or string identifier.

Resolving a Class-based Provider

const logger = providerManager.get(Logger)
logger.log('Hello from Logger')

Resolving a Factory-based Provider with String Identifier

const mainDatabaseConnection = providerManager.get('MAIN_DATABASE')
mainDatabaseConnection.connect()

Resolving a Factory-based Provider without Identifier

const configService = providerManager.get(ConfigService)
console.log(configService.appName) // Output: MyApp

Resolving a Class-based Provider with Dependencies

When you resolve a class-based provider with dependencies, the ProviderManager automatically injects the necessary dependencies.

const userService = providerManager.get(UserService)
userService.createUser('John Doe')

Example Summary

Here's a summary example that demonstrates registering and resolving multiple types of providers:

const providerManager = new ProviderManager()
providerManager
  .registerProvider(Logger) // Class-based provider
  .registerProvider(() => new DatabaseConnection('postgresql://main-database:5432'), 'MAIN_DATABASE') // Factory-based provider with identifier
  .registerProvider(() => new DatabaseConnection('postgresql://another-database:5432'), 'ANOTHER_DATABASE') // Factory-based provider with identifier
  .registerProvider(ConfigService) // Factory-based provider without identifier
  .registerProvider(UserService) // Class-based provider with dependencies

// Resolve providers
const logger = providerManager.get(Logger)
const mainDatabaseConnection = providerManager.get('MAIN_DATABASE')
const anotherDatabaseConnection = providerManager.get('ANOTHER_DATABASE')
const configService = providerManager.get(ConfigService)
const userService = providerManager.get(UserService)

// Using resolved services
logger.log('Application started')
mainDatabaseConnection.connect()
anotherDatabaseConnection.connect()
console.log(`App Name: ${configService.appName}`)
userService.createUser('John Doe')

API

registerProvider<T>(provider: Constructor<T> | Factory<T>, identifier?: Constructor<T> | string): this

Registers a provider (either a class constructor or a factory) in the ProviderManager.

  • provider: The provider to register (constructor or factory).
  • identifier: An optional string or constructor to identify the provider. If not provided, the class name is used for constructors.

get<T>(identifier: string | Provider<T>): T

Retrieves a provider instance by its string identifier, constructor, or factory.

  • identifier: The identifier (string or provider) to resolve.

License

This project is licensed under the MIT License. See the LICENSE file for details.