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

@wssz/di

v3.0.0

Published

DI (dependency injection) lib. Cross-env with optional decorator API.

Downloads

10

Readme

@wssz/di

DI (dependency injection) lib. Cross-env with optional decorator API.

Examples

Service testing/mocking

import { bindFactory } from './helpers'
import { Scope } from './Scope'

@injectable(Lifetime.SINGLETON)
class Db {
	get(key: string) {
		// some db adapter
	}
}

@injectable()
class Service {
	db = inject(DB)

	userById(id: string) {
		return this.db.get(id)
	}
}

const module = new Module([
	bindFactory(
		() => ({
			get() {
				return {
					id: '123',
					name: 'John'
				}
			}
		}),
		DB
	)
])

const scope = new Scope(module)
const mockedServiceInstance = scope.inject(Service)
mockedServiceInstance.userById('any key') // -> { id: '123', name: 'John' }

Functions

inject(token: Token<T>)

Inject provider in current scope, need to be used on provider initialization. Used outside scope will refer to globalScope.

function factory() {
  return {
    a: inject(Class1)
  }
}

class Example {
  a = inject(Class1)

  constructor() {
    this.b = inject(Class2)
  }
	
  method() {
    // Injection outside of scope (running in globalScope)
    const c = inject(Class3)
  }
}

token(value?: T, key?: string): Token<T>

To provide type checking token function is available.

import { bindFactory } from './helpers'

interface Config {
	var: string
}

const config: Config = {
	var: '123'
}

const token1 = token<Config>()
const token2 = token(config)
const token3 = token(config, 'config')

new Module([
	bindValue(config, token1),
	bindFactory(() => ({ var: '321' }), token2),
	bindValue(config, token3),
])

// all three injections has same types
class Service {
	c1 = inject(token1)
	c2 = inject(token2)
	c3 = inject(token3)
}

onDispose(() => void)

Lifecycle dispose hook in current scope.

class Service {
  constructor() {
    onDispose(() => {
      return new Promise(res => {
        setTimeout(res, 1000)
      })
    })
  }
}

dispose()

Trigger dispose in current scope.

import { onDispose } from './helpers'

// global scope dispose hook
onDispose(() => {
	console.log('Say bye!')
})

// global scope dispose trigger
dispose()

Decorators

@injectable()

Register class for globalModule

@injectable()
class Service {}

const serviceInstance = resolve(Service)

@disposable

Mark method as onDispose

@injectable()
class Service {

  constructor() {
    // one way
    onDispose(() => this.onDispose())
  }

  // secound way
  @disposable
  onDispose() {
    console.log('disposed')
  }
}

const serviceInstance = resolve(Service)

Module

Module contains available providers to resolve

new Module(registrations: (Provider<any> | Module)[] = [])

const module = new Module([
	// clone entries from other module
	otherModule,
	// declare new entries or overite if exists in otherModule
	bindClass(Service),
	// or overite if already exists
	bindClass(ServiceMock, Service)
])

Scope

Scope contain cached providers registered () in module. Gives possibility to dispose services created in scope.

new Scope(module: Module): Scope

const module = new Mdoule()
const scope = new Scope(module)

scope.inject(Service)

scope.onDispose(cb: () => void)

Hook triggered when scope is disposed.

@injectable()
class Service {
  constructor() {
    // scope.onDispose but for current scope
    onDispose(() => {
      console.log('disposed')
    })
  }
}

const scope = new Scope(globalModule)
scope.onDispose(() => {
  console.log('disposed')
})
scope.dispose() // -> 'disposed'

scope.inject(token: Token<T>): T

Resolve value registered in module or cached in scope if exists.

class Service {
	// inject of current scope
	user = inject(User)
}

const module = new Module([Service])
const scope = new Scope(module)

const service = scope.inject(Service) // or module.resolve(Service, scope)

scope.dispose(): Promise<void>

Dispose current scope, all registered onDispose hook will be triggered.

class Service {
  constructor() {
    onDispose(() => {
      return new Promise(res => {
        setTimeout(res, 1000)
      })
    })
  }
}

const module = new Module([Service])
const scope = new Scope(module)
const service = scope.inject(Service) // create instance in cache

await scope.dispose() // wait for all onDispose hooks end

Lifetime

Lifetime.SINGLETON

Services are created outside Scopes and require globally defined dependencies (by injectable). After resolution, instance is stored in declaration so if modules share same dependencies then will share also instance.

Lifetime.SCOPED

Default lifetime, cached per each scope. Disposed on scope.dispose()

Lifetime.TRANSIENT

Created each time when added by inject