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

pigly

v2.0.0-alpha.8

Published

unobtrusive, manually configured, dependency-injection for javascript/typescript

Downloads

98

Readme

Pigly

unobtrusive, manually configured, dependency-injection for javascript/typescript

alt

⚠️⚠️ WARNING: experimental - lock to minor versions ⚠️⚠️

CircleCI npm npm Codecov

Philosophy

don't pollute the code with DI concerns

pigly is a simple helper to manually configure a DI container to bind symbols to providers. It explicitly avoids decorators, or any other changes to existing code, and on its own doesn't require any other dependency / compilation-step to work. However, when combined with the typescript transformer @pigly/transformer we can reduce the amount of boiler-plate and simply describe the bindings as:

let kernel = new Kernel();

kernel.bind(toSelf(Foo));
kernel.bind(toSelf(Bar));

kernel.bind<IFoo>(to<Foo>());
kernel.bind<IBar>(to<Bar>());

let foo = kernel.get<IFoo>();

Planned features

  • Scoping
  • Better inferring of constructors

Native Usage

native usage relates to using this package directly without any typescript transformer.

Its pretty simple: create a kernel, create symbol-to-provider bindings, then get the resolved result with get(symbol)

import { Kernel } from 'pigly';

let kernel = new Kernel();

kernel.bind(Symbol.for("Foo"), (ctx)=>{ return "foo" });

let foo = kernel.get(Symbol.for("Foo"));

.bind(symbol, provider)

bind links a specific symbol to a provider of the form (context)=>value;

kernel.bind(A, _=>{ return "hello world" })

.get(symbol)

resolve all the bindings for a symbol and return the first one

const A = Symbol.for("A")

kernel.bind(A, _=> "hello");
kernel.bind(A, _=> " world");

let result = kernel.get(A); // "hello";

.getAll(symbol)

resolve all the bindings for a symbol and return all of the results.

const A = Symbol.for("A")

kernel.bind(A, _=> "hello");
kernel.bind(A, _=> " world");

let results = kernel.getAll(A); // ["hello", " world"];

Providers

to(symbol)

used to redirect a binding to and resolve it through a different symbol.

const A = Symbol.for("A")
const B = Symbol.for("B")

kernel.bind(A, to(B));
kernel.bind(B, _ => "hello world");

toAll(symbol)

used to resolve a symbol to all its bindings

const A = Symbol.for("A")
const B = Symbol.for("A");

kernel.bind(A, _ => "hello");
kernel.bind(A, _ => "world");
kernel.bind(B, toAll(A));

kernel.get(B); // ["hello", "world"]

toClass(Ctor, ...providers)

used to provide an instantiation of a class. first parameter should be the class constructor and then it takes a list of providers that will be used, in the given order, to resolve the constructor arguments.

class Foo{
  constructor(public message: string)
}

const A = Symbol.for("A")
const B = Symbol.for("B")

kernel.bind(B, _=>"hello world");
kernel.bind(A, toClass(Foo, to(B)))

toConst(value)

a more explicit way to provide a constant

kernel.bind(B, toConst("hello world"));

asSingleton(provider)

used to cache the output of the given provider so that subsequent requests will return the same result.

const A = Symbol.for("A");
const B = Symbol.for("B");

kernel.bind(A, toClass(Foo));
kernel.bind(B, asSingleton(to(A)));

when(predicate, provider)

used to predicate a provider for some condition. any provider that explicitly returns undefined is ignored

const A = Symbol.for("A");
const B = Symbol.for("B");
const C = Symbol.for("C");

kernel.bind(A, toClass(Foo, to(C) ));
kernel.bind(B, toClass(Foo, to(C) ));

kernel.bind(C, when(x=>x.parent.target == A, toConst("a")));
kernel.bind(C, when(x=>x.parent.target == B, toConst("b")));

Predicates

injectedInto(symbol)

returns true if ctx.parent.target == symbol

const A = Symbol.for("A");
const B = Symbol.for("B");
const C = Symbol.for("C");

kernel.bind(A, toClass(Foo, to(C) ));
kernel.bind(B, toClass(Foo, to(C) ));

kernel.bind(C, when(injectedInto(A), toConst("a")));
kernel.bind(C, when(injectedInto(B), toConst("b")));

hasAncestor(symbol)

returns true if an request ancestor is equal to the symbol.

  const A = Symbol.for("A");
  const B = Symbol.for("B");
  const C = Symbol.for("C");

  kernel.bind(A, when(hasAncestor(C), toConst("foo")));
  kernel.bind(A, toConst("bar")));  
  kernel.bind(B, to(A));
  kernel.bind(C, to(B));

  let c = kernel.get(C); // "foo"
  let b = kernel.get(B); // "bar"

Transformer Usage

with '@pigly/transformer' installed (see https://github.com/pigly-di/pigly/tree/develop/packages/pigly-transformerr) you are able to omit manually creating a symbol. Currently

  • .bind<T>(provider)
  • .get<T>()
  • to<T>()
  • toAll<T>()
  • toSelf<T>(Class)
  • injectedInto<T>()
  • hasAncestor<T>()
  • Inject<T>()

are supported.

Example

class Foo implements IFoo{
  constructor(public name: string){}
}

let kernel = new Kernel();

kernel.bind(toSelf(Foo));

kernel.bind<string>(
  when(injectedInto<Foo>(
    toConst("joe")));

kernel.bind<IFoo>(to<Foo>());

let foo = kernel.get<IFoo>();

toSelf(Class)

attempts to infer the constructor arguments and generate the providers needed to initialise the class. It can only do so if the constructor arguments are simple. Currently only supports the first constructor.

kernel.bind(toSelf(Foo));

is equivalent to

kernel.bind(toClass(Foo, to<IBar>, to...

SymbolFor()

calls to SymbolFor() get replaced with symbol.for("<T>") through @pigly/transformer and can be used if you want to be closer to the native usage i.e.

let kernel = new Kernel();

const $IFoo = SymbolFor<IFoo>();
const $IBar = SymbolFor<IBar>();

kernel.bind<IFoo>($IFoo, toClass(Foo, to<IBar>($IBar)));
kernel.bind<IBar>($IBar, toClass(Bar));

let foo = kernel.get<IFoo>($IFoo);

The current approach in the transformer, to make the type's symbol, is to use the imported name directly i.e. SymbolFor<IFoo>() is converted to Symbol.for("IFoo"). The intention here is to give most flexibility and consistently in how the Symbols are created, especially if you want to configure a container across multiple independently-compiled libraries, or when using the transformer in a "transform only" build stage, as is typically the case with Webpack and Vue. The downside is that you must be consistent with type names, avoid renaming during imports and do not implement two or more interfaces with the exact same identifier-name.

License

MIT

Credits

"pig" licensed under CC from Noun Project, Created by habione 404, FR

@pigly/transformer was derived from https://github.com/YePpHa/ts-di-transformer (MIT)