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

krispy

v2.0.0

Published

Basic synchronous dependency injector

Downloads

14

Readme

Build Status

krispy

A pretty simple dependency injector.

It works pretty ok.

Features

  • Optional global instance shared across all usages
  • Inheritance checking
  • Transient and Singleton resolution
  • Requires very little setup (1 line to register a base/subclass, 1 line to resolve)
  • Zero production dependencies

Basic Usage (TypeScript):

import Injector from 'krispy';

abstract class IBaseClass {
    abstract doSomeAction(): void;   
}

class ImplementedClass extends IBaseClass {
    doSomeAction(): void {
        console.log('Hello World!');
    }
}

// Optionally, you can add the generics for <IBaseClass, ImplementedClass>
Injector.global.addSingleton(IBaseClass, ImplementedClass);

const impl: IBaseClass = Injector.global.resolve(IBaseClass);

// logs 'Hello World!'
impl.doSomeAction();

Advanced Usage/Information

Abstract Classes

Because TypeScript types and interfaces do not exist at runtime, you MUST use an abstract class to register or resolve dependencies. Otherwise the injector literally gets nothing since interfaces just do not exist. If you are dead-set on interfaces, some editors like WebStorm will generate the abstract members for you from an interface.

If you're using vanilla JS, non abstract classes will work fine of course, but the fact that you can't enforce any kind of implementation contract makes this pretty useless to install.

Type Resolution

Again, since there are no real types in TypeScript we unfortunately cannot use fancy reflection or anything like you can in Java/C#/etc. Instead, it just uses the .name of the abstract class you pass, e.g. class MyClass has a .name of MyClass.

Name your classes well, I guess. It's more important when you are using a global injector.

I considered using prototypes to match types, but that seems really cumbersome and probably not performant. Plus I'm pretty sure typescript gets rid of abstract stuff when compiling.

Duplicate entries

If you register a dependency twice, it will just overwrite the last one.

Injection Type

To inject, you can call addTransient, addSingleton, or add (but you have to provide the injection type after the base and inherited class)

The difference is simple:

  • Transient is instantiated each time its type is resolved with injector.resolve
  • Singleton is only instantiated the first time its type is resolved, and then that instance is cached and returned.

Instantiation

global

If you don't want to deal with instantiating an Injector and passing it around, you can use the global static getter on Injector. If you don't use global the instance is never instantiated, so nothing is just sitting around in memory.

instantiated

Injector has no constructor parameters, so if you want to make a local injector...

import Injector from 'krispy';

const injector = new Injector();

global vs instantiated

Because types are resolved by name, using global can be dangerous in some cases if your abstract classes are named really generically (such as "Logger" or "Debug" or "Database", etc.). Since duplicates just overwrite each other, you may not end up with the same type as you expect from the global injector.

I expect exactly 0 people to be using this module so go nuts with global.

Exceptions / Errors

I can't promise any expectations of functionality if you are not using typescript. Unless it is a legitimate bug that happens with TS too, any errors from bad types or values being passed to methods is not my concern.

Registration

  • Make sure your base class is actually the base class of the inherited class when you register a dependency, or you'll get a CannotRegisterDependencyException

Resolution

  • If you try to resolve an unregistered dependency, you'll get an UnresolvableDependencyException
  • If something went horribly wrong and the internal data for a dependency is null, you'll get an UnresolvableDependencyException.
  • If something went horribly wrong and the injection type is invalid, you'll get an UnexpectedStateException