Socket
Socket
Sign inDemoInstall

mana-syringe

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mana-syringe - npm Package Compare versions

Comparing version 0.1.0 to 0.2.0

dist/contribution/contribution-protocol.d.ts

12

dist/container.d.ts
import { Container as InversifyContainer } from 'inversify';
import type { InversifyContext } from './inversify';
import type { InversifyContext } from './inversify/inversify-protocol';
import type { Syringe } from './core';
import type { SyringeModule } from './module';
export declare class Container implements Syringe.Container, InversifyContext {
static config(option: Syringe.InjectOption<void>): void;
protected loadedModule: number[];
protected loadedModules: number[];
container: InversifyContainer;
inversify: boolean;
protected inversify: boolean;
parent?: Container;
constructor(inversifyContainer?: InversifyContainer);
load(module: SyringeModule, force?: boolean): void;
load(module: Syringe.Module, force?: boolean): void;
remove<T>(token: Syringe.Token<T>): void;

@@ -21,3 +20,4 @@ get<T>(token: Syringe.Token<T>): T;

createChild(): Syringe.Container;
register<T = any>(token: Syringe.Token<T> | Syringe.InjectOption<T>, options?: Syringe.InjectOption<T>): void;
register<T = any>(tokenOrOption: Syringe.Token<T> | Syringe.InjectOption<T>): void;
register<T = any>(token: Syringe.Token<T>, options: Syringe.InjectOption<T>): void;
protected resolveContext(): Syringe.Context;

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

@@ -1,4 +0,11 @@

export * from './interface';
export * from './provider';
export * from './contribution';
import * as Protocol from './contribution-protocol';
import { contributionRegister } from './contribution-register';
export * from './contribution-protocol';
export * from './contribution-provider';
export * from './decorator';
export declare namespace Contribution {
type Option = Protocol.Option;
type Provider<T extends Record<string, any>> = Protocol.Provider<T>;
const Provider: import("..").Syringe.DefinedToken;
const register: typeof contributionRegister;
}

@@ -42,2 +42,3 @@ import 'reflect-metadata';

};
function isModule(data: Record<any, any> | undefined): data is Module;
type Container = {

@@ -44,0 +45,0 @@ parent?: Container;

import type { interfaces } from 'inversify';
import type { InversifyContext } from './inversify';
import type { InversifyContext } from './inversify/inversify-protocol';
import { Syringe } from './core';

@@ -24,3 +24,3 @@ export declare function toRegistryOption<P>(options: Syringe.InjectOption<P>): Syringe.FormattedInjectOption<P>;

protected context: Syringe.Container;
protected mutipleEnable: boolean;
protected mutiple: boolean;
constructor(context: Syringe.Container, token: Syringe.UnionToken<T>, option: Syringe.FormattedInjectOption<T>);

@@ -27,0 +27,0 @@ /**

{
"name": "mana-syringe",
"keywords": [],
"version": "0.1.0",
"version": "0.2.0",
"typings": "dist/index.d.ts",

@@ -19,3 +19,3 @@ "main": "dist/index.js",

"devDependencies": {
"mana-scripts": "^0.1.0"
"mana-scripts": "^0.2.0"
},

@@ -29,3 +29,3 @@ "scripts": {

},
"gitHead": "6b8dca016bab39959aecfa75e4e35dc76efcae91"
"gitHead": "6d25a80429a48414e6d8291097c9a335b83e20e9"
}

@@ -13,5 +13,5 @@ # mana-syringe

## 概念
## 概念与使用
1. 注入标识 token
### 注入标识 token

@@ -24,48 +24,12 @@ 注入绑定对象所使用的的标识,可以带有一定的类型约束

我们可以比较开放的使用标识,考虑到多包的协作,一般会使用 symbol 类型,标识默认支持单绑定,需要使用多绑定时,应该使用 Syringe.defineToken 方法获得,其接受是否可多绑定的设置。
除 `Syringe.DefinedToken<T>` 默认支持多绑定外,注入标识只支持单一绑定关系。可以使用如下 API 生成 DefinedToken
2. 容器 Container
包含一组绑定标识与注入对象关系描述的上下文成为容器,当我们通过容器获取实例时,容器会根据注入对象及其与标识的关系自动构建所需的其他实例。
3. 生命期 lifecycle
容器会根据注入对象的生命期描述托管这些对象。
```typescript
export enum Lifecycle {
singleton = 'singleton',
transient = 'transient',
}
Syringe.defineToken('sample-token');
```
## 使用
### 容器 Container
### 装饰器
包含一组绑定标识与注入对象关系描述的上下文成为容器,当我们通过容器获取实例时,容器会根据注入对象及其与标识的关系自动构建所需的其他实例。
我们提供了一组对类与属性的装饰器函数,用来快速完成基于依赖注入的类型描述,并完成基本的绑定关系描述。
- injectable: 通用装饰器,接受所有绑定描述参数
- singleton: 单例装饰器,接受除生命期外的描述参数
- transient: 多例装饰器,接受除生命期外的描述参数
- inject: 注入,接受注入标识作为参数,并接受类型描述
```typescript
@singleton()
class Shuriken implements Weapon {
public hit() {
console.log('Shuriken hit');
}
}
@transient()
class Ninja {
@inject(Weapon) public weapon: Weapon;
public hit() {
this.weapon.hit();
}
}
```
### 容器
用户可以手动创建容器,使用全局默认的容器,或者创建子容器

@@ -80,4 +44,12 @@

### 注册
我们使用 `token` 从容器里获取对象
```typescript
const ninja = child.get(Ninja);
```
当我们从子容器中获取对象时,会先从子容器查找绑定关系和缓存信息,如果不存在,则继续向父容器查找。
### 注册 register
容器上暴露了 register 方法,这个 API 是整个体系的核心。 register 方法有两种签名

@@ -108,3 +80,2 @@

- contrib 可以为数组,可用于注册扩展点,也可用于注册 token 别名
- lifecycle 生命期,参见前文
- useClass 可以为数组,给出一个或多个类

@@ -116,4 +87,17 @@ - useToken 可以为数组,根据 token 从容器内动态获取对象

#### 生命期 lifecycle
容器会根据注入对象的生命期描述托管这些对象,决定是否使用缓存等。
```typescript
@singleton()
export enum Lifecycle {
singleton = 'singleton',
transient = 'transient',
}
```
#### 注册类和别名
```typescript
@singleton({ contrib: Alias })
class Shuriken implements Weapon {

@@ -125,22 +109,99 @@ public hit() {

GlobalContainer.register(Shuriken);
GlobalContainer.register({ token: Shuriken, useClass: Shuriken });
GlobalContainer.register(Shuriken, {
useClass: Shuriken,
lifecycle: Syringe.Lifecycle.singleton,
});
```
### 模块
通过 token 注册后,每个 token 的注册关系是独立的,通过他们获取对象可以是不同的值,通过 contrib 注册的是别名关系,他们应该获取到同一个对象。不管是 token 还是 contrib,根据对多绑定的支持情况做处理。
可以通过用一组注册动作创建一个模块,方便在不同容器上下文间内加载
```typescript
const Weapon = Symbol('Weapon');
const WeaponArray = Syringe.defineToken('Weapon');
@singleton({ contrib: Weapon })
class Shuriken implements Weapon {
public hit() {
console.log('Shuriken hit');
}
}
GlobalContainer.register({ token: Weapon, useValue: undefined });
GlobalContainer.register({ token: WeaponArray, useValue: undefined });
GlobalContainer.register(Shuriken);
GlobalContainer.get(Weapon); // Shuriken
GlobalContainer.getAll(WeaponArray); // [undefined, Shuriken]
```
#### 注册值
```typescript
const module = Module(register => {
register(Shuriken);
const ConstantValue = Symbol('ConstantValue');
GlobalContainer.register({ token: ConstantValue, useValue: {} });
```
#### 注册动态值
```typescript
const NinjaAlias = Symbol('NinjaAlias');
GlobalContainer.register({
token: NinjaAlias,
useDynamic: ctx => ctx.container.get(Ninja),
});
GlobalContainer.load(module);
```
### 扩展点
### 装饰器
为了方便注册扩展点,容器提供了一组扩展的注册与使用接口。扩展点定义使用的 token 必须为 DefinedToken。
我们提供了一组对类与属性的装饰器函数,用来快速完成基于依赖注入的类型描述,并完成基本的绑定关系描述。
- injectable: 通用装饰器,接受所有绑定描述参数
- singleton: 单例装饰器,接受除生命期外的描述参数
- transient: 多例装饰器,接受除生命期外的描述参数
- inject: 注入,接受注入标识作为参数,并接受类型描述
```typescript
@singleton()
class Shuriken implements Weapon {
public hit() {
console.log('Shuriken hit');
}
}
@transient()
class Ninja {
@inject(Weapon) public weapon: Weapon;
public hit() {
this.weapon.hit();
}
}
```
### 扩展点 Contribution
我们通常将依赖注入的多绑定模式以扩展点的形式使用,为了方便在项目中使用这种模式,我们内置了对扩展点的定义和支持。
#### 扩展点的定义与注册
```typescript
const Waepon = Syringe.defineToken('Weapon');
Contribution.register(GlobalContainer.register, Waepon);
```
#### 扩展服务 Contribution.Provider
内置了扩展点的管理服务,用户一般直接使用即可,注册扩展点以后,通过如下方式获取扩展服务
```typescript
@contrib(Weapon) public weaponProvider: Contribution.Provider<Weapon>;
```
等价于如下写法
```typescript
@inject(Contribution.Provider) @named(Weapon) public weaponProvider: Contribution.Provider<Weapon>;
```
#### 扩展点示例
```typescript
const Waepon = Syringe.defineToken('Weapon');
Contribution.register(GlobalContainer.register, Waepon);
@singleton({ contrib: Weapon })

@@ -152,2 +213,10 @@ class Shuriken implements Weapon {

}
@transient()
class Ninja {
@contrib(Weapon) public weaponProvider: Contribution.Provider<Weapon>;
hit() {
const weapons = this.weaponProvider.getContributions();
weapons.forEach(w => w.hit());
}
}
const module = Module(register => {

@@ -158,13 +227,17 @@ Contribution.register(register, Weapon);

});
GlobalContainer.register(Shuriken);
GlobalContainer.register(Ninja);
GlobalContainer.get(Ninja).hit(); // Shuriken hit
```
@transient()
class Ninja {
@contrib(Weapon) public weapons: Weapon[];
}
### 模块
可以通过用一组注册动作创建一个模块,方便在不同容器上下文间内加载, 模块的构建支持注册函数和链式调用两种方式,前面扩展点示例里的模块也可以写成如下形式:
```typescript
const module = Module().contribution(Weapon).register(Shuriken, Ninja);
GlobalContainer.load(module);
```
## 其他
1. 相同 module 默认不重复加载。
2. Contribution 可以通过多种传参形式处理缓存及是否从父组件获取。
3. 除非通过 defineToken 声明允许多绑定,token 默认单一绑定,重复注册时进行替换操作。
- 相同 module 默认不重复加载。

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

import assert from 'power-assert';
import assert from 'assert';
import { register, GlobalContainer, Container } from './container';

@@ -102,2 +102,8 @@ import { singleton, transient, injectable } from './decorator';

});
it('#undefined value', () => {
const TokenSymbol = Symbol('UndefinedToken');
register({ token: TokenSymbol, useValue: undefined });
const foo1 = GlobalContainer.get(TokenSymbol);
assert(typeof foo1 === 'undefined');
});
it('#get all', () => {

@@ -164,2 +170,18 @@ const token = Syringe.defineToken('token');

});
it('#contrib to mono/multi token', () => {
const FooSymbol = Symbol('FooSymbol');
const BarSymbol = Syringe.defineToken('BarSymbol');
register({ token: FooSymbol, useValue: FooSymbol });
register({ token: BarSymbol, useValue: undefined });
@singleton({ contrib: [FooSymbol, BarSymbol] })
class FooContribToMonoMulti {}
register(FooContribToMonoMulti);
const obj = GlobalContainer.get(FooContribToMonoMulti);
const objFoo = GlobalContainer.get(FooSymbol);
const barList = GlobalContainer.getAll(BarSymbol);
assert(obj === objFoo);
assert(barList.includes(objFoo));
assert(barList.includes(undefined));
assert(barList.length === 2);
});
it('#remove', () => {

@@ -166,0 +188,0 @@ @singleton()

import { Container as InversifyContainer } from 'inversify';
import type { InversifyContext } from './inversify';
import type { InversifyContext } from './inversify/inversify-protocol';
import {

@@ -11,3 +11,2 @@ GlobalContainer as InversifyGlobalContainer,

import { Register } from './register';
import type { SyringeModule } from './module';

@@ -19,5 +18,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */

}
protected loadedModule: number[] = [];
protected loadedModules: number[] = [];
container: InversifyContainer;
inversify: boolean = true;
protected inversify: boolean = true;
parent?: Container;

@@ -31,6 +30,6 @@ constructor(inversifyContainer?: InversifyContainer) {

}
load(module: SyringeModule, force?: boolean): void {
if (force || !this.loadedModule.includes(module.id)) {
load(module: Syringe.Module, force?: boolean): void {
if (force || !this.loadedModules.includes(module.id)) {
module.registry(this.register.bind(this), this.resolveContext());
this.loadedModule.push(module.id);
this.loadedModules.push(module.id);
}

@@ -68,2 +67,4 @@ }

}
register<T = any>(tokenOrOption: Syringe.Token<T> | Syringe.InjectOption<T>): void;
register<T = any>(token: Syringe.Token<T>, options: Syringe.InjectOption<T>): void;
register<T = any>(

@@ -70,0 +71,0 @@ token: Syringe.Token<T> | Syringe.InjectOption<T>,

import type { Syringe } from '../core';
import { Contribution } from './contribution';
import { inject, named } from '../decorator';
import { Provider } from './contribution-protocol';

@@ -14,3 +14,3 @@ export const contrib =

named(token)(target, targetKey, index);
inject(Contribution.Provider)(target, targetKey, index);
inject(Provider)(target, targetKey, index);
};
/* eslint-disable @typescript-eslint/no-explicit-any */
import 'reflect-metadata';
import assert from 'power-assert';
import assert from 'assert';
import { GlobalContainer } from '../container';

@@ -9,3 +9,3 @@ import { register } from '../container';

import { Contribution, contrib } from '../';
import { DefaultContributionProvider } from './provider';
import { DefaultContributionProvider } from './contribution-provider';
import { Syringe } from '../core';

@@ -12,0 +12,0 @@

@@ -1,4 +0,13 @@

export * from './interface';
export * from './provider';
export * from './contribution';
import * as Protocol from './contribution-protocol';
import { contributionRegister } from './contribution-register';
export * from './contribution-protocol';
export * from './contribution-provider';
export * from './decorator';
export namespace Contribution {
export type Option = Protocol.Option;
export type Provider<T extends Record<string, any>> = Protocol.Provider<T>;
export const { Provider } = Protocol;
export const register = contributionRegister;
}

@@ -65,2 +65,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */

};
export function isModule(data: Record<any, any> | undefined): data is Module {
return !!data && typeof data === 'object' && 'id' in data && 'registry' in data;
}
export type Container = {

@@ -67,0 +72,0 @@ parent?: Container;

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

import assert from 'power-assert';
import assert from 'assert';
import { Syringe } from './core';

@@ -10,3 +10,3 @@ import { singleton, transient, injectable } from './decorator';

const option = Reflect.getMetadata(Syringe.ClassOptionSymbol, Foo);
assert((option.target = Foo));
assert(option.target === Foo);
});

@@ -13,0 +13,0 @@ it('#injectable with option', () => {

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

import assert from 'power-assert';
import assert from 'assert';
import { injectable } from 'inversify';

@@ -47,2 +47,11 @@ import { toRegistryOption } from './register';

});
it('#undefined value', () => {
const TokenSymbol = Symbol('UndefinedToken');
const parsed = toRegistryOption({ token: TokenSymbol, useValue: undefined });
assert(parsed.token.length === 1);
assert(parsed.token.includes(TokenSymbol));
assert(parsed.useValue === undefined);
assert('useValue' in parsed);
assert(parsed.lifecycle === Syringe.DefaultOption.lifecycle);
});
});

@@ -49,0 +58,0 @@

import type { interfaces } from 'inversify';
import type { InversifyContext } from './inversify';
import type { InversifyContext } from './inversify/inversify-protocol';
import {

@@ -22,3 +22,2 @@ bindNamed,

const useFactory = Utils.maybeArrayToArray(options.useFactory);
const { useValue } = options;
const contrib = Utils.maybeArrayToArray(options.contrib);

@@ -37,4 +36,6 @@ const lifecycle = options.lifecycle || Syringe.Lifecycle.transient;

useFactory,
useValue,
};
if ('useValue' in options) {
generalOption.useValue = options.useValue;
}
return generalOption;

@@ -106,3 +107,3 @@ }

parsedOption.useFactory.length === 0 &&
parsedOption.useValue === undefined
!('useValue' in parsedOption)
) {

@@ -128,3 +129,3 @@ log('No value to register for token:', parsedOption.token);

protected context: Syringe.Container;
protected mutipleEnable: boolean;
protected mutiple: boolean;
constructor(

@@ -140,3 +141,3 @@ context: Syringe.Container,

this.named = Utils.isNamedToken(token) ? token.named : undefined;
this.mutipleEnable = !!this.named || Utils.isMultipleEnabled(this.rawToken);
this.mutiple = !!this.named || Utils.isMultipleEnabled(this.rawToken);
this.generalToken = this.rawToken;

@@ -153,3 +154,3 @@ }

}
if (this.mutipleEnable) {
if (this.mutiple) {
this.resolveMutilple(context);

@@ -159,5 +160,9 @@ } else {

if (!this.named && this.option.contrib.length > 0) {
this.option.contrib.forEach(contribution =>
bindGeneralToken(contribution, context).toService(this.generalToken),
);
this.option.contrib.forEach(contribution => {
if (Utils.isMultipleEnabled(contribution)) {
bindGeneralToken(contribution, context).toService(this.generalToken);
} else {
bindMonoToken(contribution, context).toService(this.generalToken);
}
});
}

@@ -168,4 +173,4 @@ }

protected resolveMono(context: InversifyContext): interfaces.BindingWhenOnSyntax<T> | undefined {
if (this.option.useValue !== undefined) {
return bindMonoToken(this.generalToken, context).toConstantValue(this.option.useValue);
if ('useValue' in this.option) {
return bindMonoToken(this.generalToken, context).toConstantValue(this.option.useValue!);
}

@@ -210,4 +215,4 @@ if (this.option.useDynamic.length > 0) {

const valueToBind =
this.option.useValue !== undefined
? bindGeneralToken(this.generalToken, context).toConstantValue(this.option.useValue)
'useValue' in this.option
? bindGeneralToken(this.generalToken, context).toConstantValue(this.option.useValue!)
: undefined;

@@ -214,0 +219,0 @@ if (this.named) {

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

import assert from 'power-assert';
import assert from 'assert';
import { register, GlobalContainer } from './container';

@@ -3,0 +3,0 @@ import { singleton } from './decorator';

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc