Socket
Socket
Sign inDemoInstall

@owja/ioc

Package Overview
Dependencies
0
Maintainers
1
Versions
17
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 2.0.0-alpha.3 to 2.0.0-alpha.4

dist/ioc/bind.d.ts

11

dist/index.d.ts

@@ -1,6 +0,7 @@

export { Container, Plugin } from "./ioc/container";
export { createDecorator } from "./ioc/decorator";
export { createWire } from "./ioc/wire";
export { createResolve } from "./ioc/resolve";
export { NOCACHE, NOPLUGINS } from "./ioc/symbol";
export { Container } from "./ioc/container";
export type { Plugin, Factory, Item, NewAble, Token, Value } from "./ioc/types";
export { createDecorator } from "./ioc/createDecorator";
export { createWire } from "./ioc/createWire";
export { createResolve } from "./ioc/createResolve";
export { NOCACHE, NOPLUGINS } from "./ioc/tags";
export { token } from "./ioc/token";

@@ -1,2 +0,2 @@

function t(t){return"symbol"!=typeof t}function n(n){return t(n)?`Token(${n.type.toString()})`:n.toString()}function i(n){return t(n)?n.type:n}const r=Symbol("NOCACHE"),o=Symbol("NOPLUGINS");class e{constructor(t){this.t=void 0,this.t=t}withPlugin(t){return this.t.plugins.push(t),this}}class s extends e{inSingletonScope(){return this.t.singleton=!0,this}}class u{constructor(t){this.t=void 0,this.t=t}to(t){return this.t.factory=()=>new t,new s(this.t)}toFactory(t){return this.t.factory=t,new s(this.t)}toValue(t){if(void 0===t)throw"cannot bind a value of type undefined";return this.t.value=t,new e(this.t)}}function h(t,n,i,o,e){Object.defineProperty(t,n,{get:function(){const t=i.get(o,e,this);return-1===e.indexOf(r)&&Object.defineProperty(this,n,{value:t,enumerable:!0}),t},configurable:!0,enumerable:!0})}exports.Container=class{constructor(){this.i=new Map,this.o=[],this.u=[]}bind(t){return new u(this.h(t))}rebind(t){return this.remove(t).bind(t)}remove(t){if(void 0===this.i.get(i(t)))throw`${n(t)} was never bound`;return this.i.delete(i(t)),this}get(t,r,e){void 0===r&&(r=[]);const s=this.i.get(i(t));if(void 0===s)throw`nothing bound to ${n(t)}`;const{factory:u,value:h,cache:c,singleton:f,plugins:a}=s,d=n=>{if(-1!==r.indexOf(o))return n;for(const i of this.u.concat(a))i(n,e,r,t,this);return n};if(void 0!==h)return d(h);if(void 0!==u)return d((l=()=>u(),f&&void 0!==c?c:f?(s.cache=l(),s.cache):l()));var l;throw`nothing is bound to ${n(t)}`}addPlugin(t){return this.u.push(t),this}snapshot(){return this.o.push(new Map(this.i)),this}restore(){return this.i=this.o.pop()||this.i,this}h(t){if(void 0!==this.i.get(i(t)))throw`object can only bound once: ${n(t)}`;const r={plugins:[]};return this.i.set(i(t),r),r}},exports.NOCACHE=r,exports.NOPLUGINS=o,exports.createDecorator=function(t){return function(n){return(i,r)=>{h(i,r,t,n,[].slice.call(arguments,1))}}},exports.createResolve=function(t){return function(n){var i=[].slice.call(arguments,1);let o;return function(){return-1===i.indexOf(r)&&void 0!==o||(o=t.get(n,i,this)),o}}},exports.createWire=function(t){return function(n,i,r){h(n,i,t,r,[].slice.call(arguments,3))}},exports.token=function(t){return{type:Symbol(t)}};
class t{constructor(t){this.t=void 0,this.t=t}withPlugin(t){return this.t.plugins.push(t),this}}class n extends t{inSingletonScope(){return this.t.singleton=!0,this}}class i{constructor(t){this.t=void 0,this.t=t}to(t){return this.t.injected=()=>new t,new n(this.t)}toFactory(t){return this.t.injected=t,new n(this.t)}toValue(n){if(void 0===n)throw"cannot bind a value of type undefined";return this.t.injected=n,new t(this.t)}}const e=t=>"symbol"!=typeof t,o=t=>e(t)?`Token(${t.type.toString()})`:t.toString(),r=t=>e(t)?t.type:t,s=Symbol("NOCACHE"),u=Symbol("NOPLUGINS");function h(t,n,i,e,o){Object.defineProperty(t,n,{get:function(){const t=i.get(e,o,this);return-1===o.indexOf(s)&&Object.defineProperty(this,n,{value:t,enumerable:!0}),t},configurable:!0,enumerable:!0})}exports.Container=class{constructor(){this.i=new Map,this.o=[],this.u=[]}bind(t){return new i(this.h(t))}rebind(t){return this.remove(t).bind(t)}remove(t){if(void 0===this.i.get(r(t)))throw`${o(t)} was never bound`;return this.i.delete(r(t)),this}get(t,n,i){void 0===n&&(n=[]);const e=this.i.get(r(t));if(void 0===e||void 0===e.injected)throw`nothing bound to ${o(t)}`;const s="function"==typeof e.injected?e.singleton?e.cache=e.cache||e.injected():e.injected():e.injected;return-1===n.indexOf(u)&&e.plugins.concat(this.u).forEach(e=>{e(s,i,n,t,this)}),s}addPlugin(t){return this.u.push(t),this}snapshot(){return this.o.push(new Map(this.i)),this}restore(){return this.i=this.o.pop()||this.i,this}h(t){if(void 0!==this.i.get(r(t)))throw`object can only bound once: ${o(t)}`;const n={plugins:[]};return this.i.set(r(t),n),n}},exports.NOCACHE=s,exports.NOPLUGINS=u,exports.createDecorator=function(t){return function(n){var i=[].slice.call(arguments,1);return function(e,o){h(e,o,t,n,i)}}},exports.createResolve=function(t){return function(n){var i=[].slice.call(arguments,1);let e;return function(){return-1===i.indexOf(s)&&void 0!==e||(e=t.get(n,i,this)),e}}},exports.createWire=function(t){return function(n,i,e){h(n,i,t,e,[].slice.call(arguments,3))}},exports.token=t=>({type:Symbol(t)});
//# sourceMappingURL=ioc.js.map

@@ -1,30 +0,3 @@

import { MaybeToken } from "./token";
interface Item<T> {
factory?: Factory<T>;
value?: Value<T>;
cache?: T;
singleton?: boolean;
plugins: Plugin<T>[];
}
export declare type Plugin<Dependency = any, Target = any> = (dependency: Dependency, target: Target | undefined, args: symbol[], token: MaybeToken<Dependency>, container: Container) => void;
interface NewAble<T> {
new (...args: any[]): T;
}
declare type Factory<T> = () => T;
declare type Value<T> = T;
declare class PluginOptions<T> {
protected _target: Item<T>;
constructor(_target: Item<T>);
withPlugin(plugin: Plugin<T>): PluginOptions<T>;
}
declare class Options<T> extends PluginOptions<T> {
inSingletonScope(): PluginOptions<T>;
}
declare class Bind<T> {
private _target;
constructor(_target: Item<T>);
to(object: NewAble<T>): Options<T>;
toFactory(factory: Factory<T>): Options<T>;
toValue(value: Value<T>): PluginOptions<T>;
}
import type { MaybeToken, Plugin } from "./types";
import { Bind } from "./bind";
export declare class Container {

@@ -37,8 +10,7 @@ private _registry;

remove(token: MaybeToken): Container;
get<T = never>(token: MaybeToken<T>, args?: symbol[], target?: unknown): T;
get<T = never>(token: MaybeToken<T>, tags?: symbol[], target?: unknown): T;
addPlugin(plugin: Plugin): Container;
snapshot(): Container;
restore(): Container;
private _create;
private _createItem;
}
export {};

@@ -0,5 +1,5 @@

import type { MaybeToken } from "./types";
import { Container } from "./container";
import { MaybeToken } from "./token";
export declare function define<T, Target extends {
[key in Prop]: T;
}, Prop extends string>(target: Target, property: Prop, container: Container, token: MaybeToken<T>, args: symbol[]): void;
}, Prop extends keyof Target>(target: Target, property: Prop, container: Container, token: MaybeToken<T>, tags: symbol[]): void;

@@ -1,10 +0,4 @@

export declare function token<T>(name: string): Token<T>;
declare const typeMarker: unique symbol;
export interface Token<T> {
type: symbol;
[typeMarker]: T;
}
export declare type MaybeToken<T = unknown> = Token<T> | symbol;
export declare function stringifyToken(token: MaybeToken): string;
export declare function getType(token: MaybeToken): symbol;
export {};
import type { MaybeToken, Token } from "./types";
export declare const token: <T>(name: string) => Token<T>;
export declare const stringifyToken: (token: MaybeToken) => string;
export declare const getType: (token: MaybeToken) => symbol;
{
"name": "@owja/ioc",
"version": "2.0.0-alpha.3",
"version": "2.0.0-alpha.4",
"description": "dependency injection for javascript",

@@ -50,3 +50,3 @@ "main": "dist/ioc.js",

"@owja/typescript-config": "^1.0.2",
"@types/jest": "^27.5.1",
"@types/jest": "^28.1.7",
"@typescript-eslint/eslint-plugin": "^5.25.0",

@@ -53,0 +53,0 @@ "@typescript-eslint/parser": "^5.25.0",

@@ -5,2 +5,3 @@ # @owja/ioc

[![size](https://img.badgesize.io/https://unpkg.com/@owja/ioc/dist/ioc.js.svg?compression=brotli&label=size&v=1)](https://unpkg.com/@owja/ioc/dist/ioc.js)
[![CircleCI](https://dl.circleci.com/status-badge/img/gh/owja/ioc/tree/master.svg?style=shield)](https://dl.circleci.com/status-badge/redirect/gh/owja/ioc/tree/master)

@@ -253,3 +254,3 @@ This library implements dependency injection for javascript and typescript.

## Type-Safe Token (new in 2.0)
## :new: Type-Safe Token (new in 2.0)

@@ -285,4 +286,131 @@ With version 2 we added the possibility to use a type-safe way to identify our dependencies. This is done with tokens:

## Usage
## :new: Plugins (new in 2.0)
Plugins are a way to hook into the dependency resolving process and execute code which can
access the dependency and also the dependent object.
A plugin can add directly to a dependency or to the container.
```ts
container.bind(symbol).to(MyService).withPlugin(plugin);
```
```ts
container.addPlugin(plugin);
```
The plugin is a simple function which has access to the dependency, the target (the instance which requires the dependency),
the arguments which are passed, the token or symbol which represents the dependency and the container.
```ts
type Plugin<Dependency = unknown> = (
dependency: Dependency,
target: unknown,
args: symbol[],
token: MaybeToken<Dependency>,
container: Container,
) => void;
```
### Plugin Example
The following code is a plugin which links a preact view component to a service by calling forceUpdate every time the
service executes the listener:
```ts
import {Plugin} from "@owja/ioc";
import {Component} from "preact";
export const SUBSCRIBE = Symbol();
export const serviceListenerPlugin: Plugin<Listenable> = (service, component, args) => {
if (args.indexOf(SUBSCRIBE) === -1 || !component) return;
if (!isComponent(component)) return;
const unsubscribe = service.listen(() => component.forceUpdate());
const unmount = component.componentWillUnmount;
component.componentWillUnmount = () => {
unsubscribe();
unmount?.();
};
};
function isComponent(target: unknown) : target is Component {
return !!target && typeof target === "object" && "forceUpdate" in target;
}
interface Listenable {
listen(listener: () => void): () => void;
}
```
> Note: this will fail on runtime if `service` does not implement the `Listenable` interface because there is no type checking done
This plugin is added to the dependency directly:
```ts
const TYPE = {
TranslationService: token<TranslatorInterface>("translation-service"),
};
container
.bind<TranslatorInterface>(TYPE.TranslationService)
.toFactory(translationFactory)
.inSingletonScope()
.withPlugin(serviceListenerPlugin);
```
In a component it is then executed when the dependency is resolved:
```ts
class Index extends Component {
@inject(TYPE.TranslationService, SUBSCRIBE)
readonly service!: TranslatorInterface;
render() {
return (
<div>{this.service.t("greeting")}</div>
);
}
}
```
This works also with `wire` and `resolve`:
```ts
class Index extends Component {
readonly service!: TranslatorInterface;
constructor() {
super();
wire(this, "service", TYPE.TranslationService, SUBSCRIBE);
}
[...]
}
class Index extends Component {
readonly service = resolve(TYPE.TranslationService, SUBSCRIBE);
[...]
}
```
### Prevent Plugins from Execution
In case you add a plugin it is executed every time the dependency is resolved. If you want to prevent this you can
add the `NOPLUGINS` tag to the arguments:
```ts
import {NOPLUGINS} from "@owja/ioc";
class Example {
@inject(TYPE.MyService, NOPLUGINS)
readonly service!: MyServiceInterface;
}
```
## Getting Started
#### Step 1 - Installing the OWJA! IoC library

@@ -289,0 +417,0 @@

@@ -1,6 +0,7 @@

export {Container, Plugin} from "./ioc/container";
export {createDecorator} from "./ioc/decorator";
export {createWire} from "./ioc/wire";
export {createResolve} from "./ioc/resolve";
export {NOCACHE, NOPLUGINS} from "./ioc/symbol";
export {Container} from "./ioc/container";
export type {Plugin, Factory, Item, NewAble, Token, Value} from "./ioc/types";
export {createDecorator} from "./ioc/createDecorator";
export {createWire} from "./ioc/createWire";
export {createResolve} from "./ioc/createResolve";
export {NOCACHE, NOPLUGINS} from "./ioc/tags";
export {token} from "./ioc/token";

@@ -1,74 +0,15 @@

import {getType, MaybeToken, stringifyToken} from "./token";
import {NOPLUGINS} from "./symbol";
import type {Factory, Injected, Item, MaybeToken, Plugin} from "./types";
import {Bind} from "./bind";
import {getType, stringifyToken} from "./token";
import {NOPLUGINS} from "./tags";
interface Item<T> {
factory?: Factory<T>;
value?: Value<T>;
cache?: T;
singleton?: boolean;
plugins: Plugin<T>[];
}
const isFactory = <T>(i: Injected<T>): i is Factory<T> => typeof i === "function";
export type Plugin<Dependency = any, Target = any> = (
dependency: Dependency,
target: Target | undefined,
args: symbol[],
token: MaybeToken<Dependency>,
container: Container,
) => void;
interface NewAble<T> {
new (...args: any[]): T;
}
type Registry = Map<symbol, Item<any>>;
type Factory<T> = () => T;
type Value<T> = T;
class PluginOptions<T> {
constructor(protected _target: Item<T>) {}
withPlugin(plugin: Plugin<T>): PluginOptions<T> {
this._target.plugins.push(plugin);
return this;
}
}
class Options<T> extends PluginOptions<T> {
inSingletonScope(): PluginOptions<T> {
this._target.singleton = true;
return this;
}
}
class Bind<T> {
constructor(private _target: Item<T>) {}
to(object: NewAble<T>): Options<T> {
this._target.factory = () => new object();
return new Options<T>(this._target);
}
toFactory(factory: Factory<T>): Options<T> {
this._target.factory = factory;
return new Options<T>(this._target);
}
toValue(value: Value<T>): PluginOptions<T> {
if (typeof value === "undefined") {
throw "cannot bind a value of type undefined";
}
this._target.value = value;
return new PluginOptions<T>(this._target);
}
}
export class Container {
private _registry: Registry = new Map<symbol, Item<any>>();
private _snapshots: Registry[] = [];
private _registry = new Map<symbol, Item<unknown>>();
private _snapshots: typeof this._registry[] = [];
private _plugins: Plugin[] = [];
bind<T = never>(token: MaybeToken<T>): Bind<T> {
return new Bind<T>(this._create<T>(token));
return new Bind<T>(this._createItem<T>(token));
}

@@ -81,5 +22,3 @@

remove(token: MaybeToken): Container {
if (this._registry.get(getType(token)) === undefined) {
throw `${stringifyToken(token)} was never bound`;
}
if (this._registry.get(getType(token)) === undefined) throw `${stringifyToken(token)} was never bound`;

@@ -91,32 +30,19 @@ this._registry.delete(getType(token));

get<T = never>(token: MaybeToken<T>, args: symbol[] = [], target?: unknown): T {
const item = this._registry.get(getType(token));
get<T = never>(token: MaybeToken<T>, tags: symbol[] = [], target?: unknown): T {
const item = <Item<T> | undefined>this._registry.get(getType(token));
if (item === undefined) {
throw `nothing bound to ${stringifyToken(token)}`;
}
if (item === undefined || item.injected === undefined) throw `nothing bound to ${stringifyToken(token)}`;
const {factory, value, cache, singleton, plugins} = item;
const value = isFactory(item.injected)
? !item.singleton
? item.injected()
: (item.cache = item.cache || item.injected())
: item.injected;
const execPlugins = (item: T): T => {
if (args.indexOf(NOPLUGINS) !== -1) return item;
if (tags.indexOf(NOPLUGINS) === -1)
item.plugins.concat(this._plugins).forEach((plugin) => {
plugin(value, target, tags, token, this);
});
for (const plugin of this._plugins.concat(plugins)) {
plugin(item, target, args, token, this);
}
return item;
};
const cacheItem = (creator: () => T): T => {
if (singleton && typeof cache !== "undefined") return cache;
if (!singleton) return creator();
item.cache = creator();
return item.cache;
};
if (typeof value !== "undefined") return execPlugins(value);
if (typeof factory !== "undefined") return execPlugins(cacheItem(() => factory()));
throw `nothing is bound to ${stringifyToken(token)}`;
return value;
}

@@ -139,6 +65,6 @@

private _create<T>(token: MaybeToken<T>): Item<T> {
if (this._registry.get(getType(token)) !== undefined) {
/* Item related */
private _createItem<T>(token: MaybeToken<T>): Item<T> {
if (this._registry.get(getType(token)) !== undefined)
throw `object can only bound once: ${stringifyToken(token)}`;
}

@@ -145,0 +71,0 @@ const item = {plugins: []};

@@ -0,6 +1,6 @@

import type {MaybeToken} from "./types";
import {Container} from "./container";
import {NOCACHE} from "./symbol";
import {MaybeToken} from "./token";
import {NOCACHE} from "./tags";
export function define<T, Target extends {[key in Prop]: T}, Prop extends string>(
export function define<T, Target extends {[key in Prop]: T}, Prop extends keyof Target>(
target: Target,

@@ -10,8 +10,8 @@ property: Prop,

token: MaybeToken<T>,
args: symbol[],
tags: symbol[],
) {
Object.defineProperty(target, property, {
get: function () {
const value = container.get<any>(token, args, this);
if (args.indexOf(NOCACHE) === -1) {
get: function <R>(this: R): T {
const value = container.get<T>(token, tags, this);
if (tags.indexOf(NOCACHE) === -1)
Object.defineProperty(this, property, {

@@ -21,3 +21,2 @@ value,

});
}
return value;

@@ -24,0 +23,0 @@ },

@@ -1,32 +0,10 @@

export function token<T>(name: string) {
return {type: Symbol(name)} as Token<T>;
}
import type {MaybeToken, Token} from "./types";
declare const typeMarker: unique symbol;
export const token = <T>(name: string) => ({type: Symbol(name)} as Token<T>);
export interface Token<T> {
type: symbol;
[typeMarker]: T;
}
const isToken = <T>(token: MaybeToken<T>): token is Token<T> => typeof token != "symbol";
export type MaybeToken<T = unknown> = Token<T> | symbol;
export const stringifyToken = (token: MaybeToken): string =>
isToken(token) ? `Token(${token.type.toString()})` : token.toString();
function isToken<T>(token: MaybeToken<T>): token is Token<T> {
return typeof token != "symbol";
}
export function stringifyToken(token: MaybeToken): string {
if (isToken(token)) {
return `Token(${token.type.toString()})`;
} else {
return token.toString();
}
}
export function getType(token: MaybeToken): symbol {
if (isToken(token)) {
return token.type;
} else {
return token;
}
}
export const getType = (token: MaybeToken): symbol => (isToken(token) ? token.type : token);

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc