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

injectx

v1.0.4

Published

A dependency injection package for javascript/typescript functional programming

Downloads

961

Readme

🚀  Installation and Documentation

npm install injectX

Support

This package can be used either in frontend or backend with the same installation and the same examples described bellow

🥙   Features

  • it's designed to do dependency injection for your functions using higher order functions
  • simple configuration and better code organization
  • built in dependency injection container
  • leverage inversion of control princple usage
  • can be used either on frontend or backend
  • can be used either in js code or typescript

📄  Usage

The Concept

This library is based on four main components:

  • A dependency that needs to be used in other code parts, it's called (dependency)
  • A consumer that consumes that injected dependency
  • A dependency injection container that holds all dependencies
  • A dependencies resolver, its a function that resolve the needed dependencies at runtime

The injection of the dependencies is run at runtime, so don't worry about the order of dependencies injection

Create a Dependency

The dependency could be anything, it could be an object, array, variable, function, class or any value you want

I will declare a function as a dependency

const getUserName = () => {
    return "john-smith"
}

It's a normal function, no magic here How can I use this function as a dependency?

you need at first bind it to the container, so you can access it from other code parts

GetContainer("default").Bind(getUsername)

GetContainer is a function exposed from InjectX, it's responsible for binding this dependency to the container, so you can access it from somewhere else. This GetContainer takes one param, which is the container name

What is the container name?

As we discussed eariler, the container is a key component in injectX, it holds a reference to all the dependencies, and because your application might scale and has multiple modules, you can define multiple containers for each module, to keep each module has it's isolated dependencis

For example supposing you have the following module:

  • OrdersModule
  • UsersModule
  • CatalogModule

Each module of these should have its own dependencies and you should avoid mixing dependencies between different modules, and to achieve that, you can define a different container for each module

The default container name for injectX is default so you can call GetContainer without passing the container name, and it will be resolved automatically to the default container

GetContainer().Bind(getUsername)

To Bind a dependency to the container you have to call Bind function which takes the following arguments

|argument name|type|required|description| |-|-|-|-| |dependency|any|true|this is the dependency you want to bind to the container, it could be any thing(number, string, object, array, function, class, map, symbol)| |options|object|false|some options you can define for the injected dependency| |options.name|string|false|you can define this to customize the name of the injected dependency, for example you can bind a number and make it's name as myValue so you can access it from anywhere using that defined name|

Create a Dependency Consumer

InjectX uses a friendly way for defining functions, which are higher order functions

Any dependency you want to declare you can define it as a higher order function, the first params of the dependency are the dependencies you want to inject in, and the second parameter is the actual params you are expecting to be sent to your function

for example suppose we have a repository function like this:

const getUserRepository = (username: string) => {
    return db.users.find(user => user.username === username)
}

You need to provide db to be able to use this function, in normal cases you will import the db into the global scope as the following:

import db from './db';

const getUserRepository = (username: string) => {
    return db.users.find(user => user.username === username)
}

but this violates the inversion of control principle, so to use the dependency injection, you want to inject db object somehow into getUserRepository You can use higher order function to do that, so your code will be changed to this

export const GetUserRepository = ({ db }: { db: DB }) => (username: string) => {
    return db.users.find(user => user.username === username)
}

In this updated example, we are defining a higher order function, the first function takes the dependencies you want to inject, and it returns another function that holds the actual implementation

How to use the higher order function?

Without InjectX you can still use higher order function pattern to do dependency injection, but you will need when you call this function to pass to it the needed dependencies, which makes it complex

With injectX there is a function called InjectIn it resolves the needed dependencies that this higher order function needs and returns a new resolved function contains the actual implementation

this function takes the following arguments:

|argument name|type|required|description| |-|-|-|-| |the higher order function|higher order function|true|this is the higher order function| |options|object|false|some options you can define to resolve the higher order function| |options.containers|string[]|false|in case you want to resolve multiple dependencies from multiple containers, then you can use this option| |options.resolveType|enum: lazy|eager|false|how do you want to resolve the dependencies, eager means the dependencies will be resolved once you call InjectIn function, however lazy will be done while running the app| |callbackName|string|false|in case you want to change the signature name of the returned function|

Example:

    export const getUserReposistory = InjectIn(GetUserRepository)

the returned const getUserRepository is basically a normal function (it's the same function that you defined) but after resolving the dependencies, then u can use this function to be injected in another consumers or call it directly

Calling the resolved function

console.log(getUserRepository("username"))

Resolve multiple dependencies from multiple containers

Sometimes you would have multiple containers and you want to inject dependencies from these containers in a function, to do that you can use options.containers

Example:

Suppose you have two containers:

  • orders
  • default

and you want to inject dependencies from each container, you can do as the following:

export const getUserReposistory = InjectIn(GetUserRepository, { containers: ['default', 'orders'] })

in this way it will inject the needed dependencies from both containers, but you also need to change the higher order function a little bit

export const GetUserRepository = ({ default: { db }, orders: { orderService } }: { default: { db: DB }, orders: { orderService: any } }) => (username: string) => {
    const user = db.users.find(user => user.username === username)
    const orders = orderService.getAllOrdersByUserId(user.id)
    return { orders, user }
}

In the above example instead of accepting one object in the higher order function, we accept two objects for the two containers, one for default container and the another for orders