smartdi 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +241 -185
- package/index.d.ts +4 -0
- package/index.js +96 -15
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -1,185 +1,241 @@
|
|
|
1
|
-
# SmartDI
|
|
2
|
-
|
|
3
|
-
A simple dependency injector based on decorators.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const
|
|
110
|
-
const
|
|
111
|
-
const
|
|
112
|
-
const
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
-
|
|
171
|
-
- args:
|
|
172
|
-
|
|
173
|
-
###
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
1
|
+
# SmartDI
|
|
2
|
+
|
|
3
|
+
A simple dependency injector based on decorators.
|
|
4
|
+
基于装饰器的简单依赖注入器。
|
|
5
|
+
|
|
6
|
+
## Installation | 安装
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install smartdi
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Prerequisites | 先决条件
|
|
13
|
+
|
|
14
|
+
Import the `reflect-metadata` package on the first line of your application.
|
|
15
|
+
在应用程序的第一行导入 `reflect-metadata` 包。
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import 'reflect-metadata'
|
|
19
|
+
|
|
20
|
+
// Your code here...
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Enable `emitDecoratorMetadata` and `experimentalDecorators` in your `tsconfig.json`.
|
|
24
|
+
在 `tsconfig.json` 中启用 `emitDecoratorMetadata` 和 `experimentalDecorators`。
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"emitDecoratorMetadata": true,
|
|
29
|
+
"experimentalDecorators": true,
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Basic Usage | 基本用法
|
|
34
|
+
|
|
35
|
+
### Singleton | 单例
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
import 'reflect-metadata'
|
|
39
|
+
import { SmartDI, Injectable, Inject } from 'smartdi';
|
|
40
|
+
|
|
41
|
+
@Injectable()
|
|
42
|
+
class ExampleService {
|
|
43
|
+
|
|
44
|
+
sayHello() {
|
|
45
|
+
console.log('Hello');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@Injectable()
|
|
51
|
+
class ExampleController {
|
|
52
|
+
|
|
53
|
+
@Inject(ExampleService)
|
|
54
|
+
private readonly myService!: ExampleService;
|
|
55
|
+
|
|
56
|
+
sayHello() {
|
|
57
|
+
this.myService.sayHello();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const controller = SmartDI.get(ExampleController);
|
|
63
|
+
controller.sayHello();
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Factory | 工厂模式
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
import 'reflect-metadata'
|
|
70
|
+
import { SmartDI, Injectable, Inject } from 'smartdi';
|
|
71
|
+
|
|
72
|
+
interface Shape {
|
|
73
|
+
area(): number;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// multiple means that the injectable is not singleton.
|
|
77
|
+
@Injectable({name: 'circle', multiple: true})
|
|
78
|
+
class Circle implements Shape {
|
|
79
|
+
|
|
80
|
+
private radius: number;
|
|
81
|
+
|
|
82
|
+
constructor(radius: number) {
|
|
83
|
+
this.radius = radius;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
area(): number {
|
|
87
|
+
return Math.PI * this.radius * this.radius;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
@Injectable({name: 'rect', multiple: true})
|
|
93
|
+
class Rect implements Shape {
|
|
94
|
+
|
|
95
|
+
private width: number;
|
|
96
|
+
private height: number;
|
|
97
|
+
|
|
98
|
+
constructor(width: number, height: number) {
|
|
99
|
+
this.width = width;
|
|
100
|
+
this.height = height;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
area(): number {
|
|
104
|
+
return this.width * this.height;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const type1 = 'circle';
|
|
110
|
+
const args1 = [5]; // radius = 5;
|
|
111
|
+
const shape1 = SmartDI.get<Shape>(type1, ...args1);
|
|
112
|
+
const area1 = shape1.area();
|
|
113
|
+
const type2 = 'rect';
|
|
114
|
+
const args2 = [3, 4]; // width = 3, height = 4;
|
|
115
|
+
const shape2 = SmartDI.get<Shape>(type2, ...args2);
|
|
116
|
+
const area2 = shape2.area();
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Circular Dependency | 循环依赖
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
import 'reflect-metadata'
|
|
124
|
+
import { SmartDI, Injectable, Inject } from 'smartdi';
|
|
125
|
+
|
|
126
|
+
@Injectable()
|
|
127
|
+
class ExampleServiceA {
|
|
128
|
+
|
|
129
|
+
@Inject(ExampleServiceB)
|
|
130
|
+
private readonly exampleServiceB!: ExampleServiceB;
|
|
131
|
+
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
@Injectable()
|
|
135
|
+
class ExampleServiceB {
|
|
136
|
+
|
|
137
|
+
@Inject(ExampleServiceA)
|
|
138
|
+
private readonly exampleServiceA!: ExampleServiceA;
|
|
139
|
+
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const serviceA = SmartDI.get(ExampleServiceA);
|
|
143
|
+
const serviceB = SmartDI.get(ExampleServiceB);
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## APIs | 接口
|
|
148
|
+
|
|
149
|
+
### @Injectable(options?)
|
|
150
|
+
|
|
151
|
+
Decorate a class as injectable. An "injectable" refers to a class that can be instantiated and injected into other components.
|
|
152
|
+
将类装饰为 `injectable`。`injectable` 类是指可以被实例化并注入到其他组件中的类。
|
|
153
|
+
|
|
154
|
+
- options: Injectable options.
|
|
155
|
+
- options: 可注入选项。
|
|
156
|
+
|
|
157
|
+
| name \| 字段名 | description \| 描述 |
|
|
158
|
+
| --- | --- |
|
|
159
|
+
| name | The name of the `injectable`. If not specified, the class name will be used.<br>`injectable` 的名称。若未指定,则使用类名。 |
|
|
160
|
+
| multiple | Whether the `injectable` is a factory. If not specified, the `injectable` is a singleton.<br>`injectable` 的是否为工厂模式。若未指定,则为单例。 |
|
|
161
|
+
| args | Default arguments of the `injectable`'s constructor. Defaults to [].<br>`injectable` 的构造函数的默认参数。默认为 []。 |
|
|
162
|
+
|
|
163
|
+
### @Inject(clue, ...args)
|
|
164
|
+
|
|
165
|
+
Decorate a property as a candidate for injection, which will be injected according to the specified clue.
|
|
166
|
+
将属性装饰为待注入的,将根据指定的线索进行注入。
|
|
167
|
+
|
|
168
|
+
- clue: Name, type, or abstract class of `injectable`.
|
|
169
|
+
- clue: `injectable` 的名称、类型或抽象类。
|
|
170
|
+
- args: Arguments to pass to constructor.
|
|
171
|
+
- args: 传递给构造函数的参数。
|
|
172
|
+
|
|
173
|
+
### @InjectArray(clue, ...args)
|
|
174
|
+
|
|
175
|
+
Decorate a property as a candidate for injection, which will be injected according to the specified clue.
|
|
176
|
+
将属性装饰为待注入的,将根据指定的线索进行注入。
|
|
177
|
+
The property's type must be `Array` and the clue must be a type. All injectables that are subtypes of the specified type will be injected.
|
|
178
|
+
属性的类型必须为 `Array`,且线索必须为 `injectable` 的类型。指定 `injectable` 类型的所有子类的 `injectable` 都将被注入。
|
|
179
|
+
|
|
180
|
+
- clue: Type or abstract class of the `injectable`.
|
|
181
|
+
- clue: `injectable` 的类型或抽象类。
|
|
182
|
+
- args: Arguments to pass to constructor.
|
|
183
|
+
- args:传递给构造函数的参数。
|
|
184
|
+
|
|
185
|
+
### SmartDI.get(clue, ...args)
|
|
186
|
+
|
|
187
|
+
Get an instance of the `injectable` by name or type.
|
|
188
|
+
根据名称或类型获取 `injectable` 的实例。
|
|
189
|
+
|
|
190
|
+
- clue: Name of the `injectable` or type of the injectable.
|
|
191
|
+
- clue: `injectable` 的名称或类型。
|
|
192
|
+
- args: Arguments to pass to constructor.
|
|
193
|
+
- args: 传递给构造函数的参数。
|
|
194
|
+
|
|
195
|
+
### SmartDI.register(clazz, options?)
|
|
196
|
+
|
|
197
|
+
Programmatically register a class as an `injectable`, serving as an alternative to the `@Injectable` decorator.
|
|
198
|
+
以编程方式注册类为 `injectable`,作为 `@Injectable` 装饰器的替代方案。
|
|
199
|
+
|
|
200
|
+
- clazz: Class to register.
|
|
201
|
+
- clazz: 要注册的类。
|
|
202
|
+
- options: Same as `@Injectable` options.
|
|
203
|
+
- options: 与 `@Injectable` 的选项相同。
|
|
204
|
+
|
|
205
|
+
### SmartDI.getArray(clue, ...args)
|
|
206
|
+
|
|
207
|
+
Get all registered subtypes of the specified type as an array.
|
|
208
|
+
以数组形式获取指定类型的所有已注册子类型的实例。
|
|
209
|
+
|
|
210
|
+
- clue: Type or abstract class of the `injectable`.
|
|
211
|
+
- clue: `injectable` 的类型或抽象类。
|
|
212
|
+
- args: Arguments to pass to constructor.
|
|
213
|
+
- args: 传递给构造函数的参数。
|
|
214
|
+
|
|
215
|
+
### SmartDI.initialize()
|
|
216
|
+
|
|
217
|
+
Create all singleton instances and invoke all methods decorated with `@PostConstruct`. Supports both synchronous and asynchronous lifecycle hooks.
|
|
218
|
+
创建所有单例实例,并调用所有使用 `@PostConstruct` 装饰的方法。支持同步和异步的生命周期钩子。
|
|
219
|
+
|
|
220
|
+
### SmartDI.uninitialize()
|
|
221
|
+
|
|
222
|
+
Clear all singleton instances in reverse registration order, invoking the `@PreDestroy` decorated methods for each.
|
|
223
|
+
按注册逆序清空所有单例实例,并调用使用 `@PreDestroy` 装饰的方法。
|
|
224
|
+
|
|
225
|
+
### @PostConstruct()
|
|
226
|
+
|
|
227
|
+
Decorate a method as a lifecycle hook, which will be invoked when `SmartDI.initialize()` is called.
|
|
228
|
+
将方法装饰为生命周期钩子,在调用 `SmartDI.initialize()` 时执行。
|
|
229
|
+
|
|
230
|
+
### @PreDestroy()
|
|
231
|
+
|
|
232
|
+
Decorate a method as a lifecycle hook, which will be invoked when `SmartDI.uninitialize()` is called.
|
|
233
|
+
将方法装饰为生命周期钩子,在调用 `SmartDI.uninitialize()` 时执行。
|
|
234
|
+
|
|
235
|
+
## Limitations
|
|
236
|
+
|
|
237
|
+
Injection is processed after construction, so do not access injectable values in the constructor.
|
|
238
|
+
注入是在构造函数执行之后再进行处理的,因此不要在构造函数中访问可注入的值。
|
|
239
|
+
|
|
240
|
+
## License
|
|
241
|
+
MIT
|
package/index.d.ts
CHANGED
|
@@ -12,8 +12,12 @@ export declare abstract class SmartDI {
|
|
|
12
12
|
static get<T>(clue: Class<T> | AbstractClass<T>, ...args: any[]): T;
|
|
13
13
|
static get<T>(name: string, ...args: any[]): T;
|
|
14
14
|
static getArray<T>(clue: Class<T> | AbstractClass<T>, ...args: any[]): T[];
|
|
15
|
+
static initialize(): Promise<void>;
|
|
16
|
+
static uninitialize(): Promise<void>;
|
|
15
17
|
}
|
|
16
18
|
export declare function Injectable(options?: InjectableOptions): ClassDecorator;
|
|
17
19
|
export declare function Inject(constructor: Class<any> | AbstractClass<any>, ...args: any[]): PropertyDecorator;
|
|
18
20
|
export declare function Inject(name: string, ...args: any[]): PropertyDecorator;
|
|
19
21
|
export declare function InjectArray(constructor: Class<any> | AbstractClass<any>, ...args: any[]): PropertyDecorator;
|
|
22
|
+
export declare function PostConstruct(): MethodDecorator;
|
|
23
|
+
export declare function PreDestroy(): MethodDecorator;
|
package/index.js
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var _a, _b;
|
|
3
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.InjectArray = exports.Inject = exports.Injectable = exports.SmartDI = void 0;
|
|
13
|
+
exports.PreDestroy = exports.PostConstruct = exports.InjectArray = exports.Inject = exports.Injectable = exports.SmartDI = void 0;
|
|
5
14
|
const $registry = Symbol('registry');
|
|
15
|
+
const $singletons = Symbol('singletons');
|
|
6
16
|
class SmartDI {
|
|
7
17
|
static register(clazz, options) {
|
|
8
18
|
const name = (options === null || options === void 0 ? void 0 : options.name) || clazz.name;
|
|
@@ -10,13 +20,16 @@ class SmartDI {
|
|
|
10
20
|
const singleton = !(options === null || options === void 0 ? void 0 : options.multiple);
|
|
11
21
|
if (SmartDI[$registry][name])
|
|
12
22
|
throw new Error(`Duplicated injectable name '${name}'!`);
|
|
13
|
-
|
|
23
|
+
const item = {
|
|
14
24
|
name,
|
|
15
25
|
class: clazz,
|
|
16
26
|
args: args,
|
|
17
27
|
singleton,
|
|
18
28
|
instance: undefined
|
|
19
29
|
};
|
|
30
|
+
if (singleton)
|
|
31
|
+
SmartDI[$singletons].push(item);
|
|
32
|
+
SmartDI[$registry][name] = item;
|
|
20
33
|
}
|
|
21
34
|
static get(clue, ...args) {
|
|
22
35
|
return SmartDI.internalGet(clue, new Set(), ...args);
|
|
@@ -24,6 +37,50 @@ class SmartDI {
|
|
|
24
37
|
static getArray(clue, ...args) {
|
|
25
38
|
return SmartDI.internalGetArray(clue, new Set(), ...args);
|
|
26
39
|
}
|
|
40
|
+
static initialize() {
|
|
41
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
42
|
+
const instances = [];
|
|
43
|
+
for (const item of SmartDI[$singletons])
|
|
44
|
+
instances.push(SmartDI.obtainInstance(item, new Set()));
|
|
45
|
+
const promises = [];
|
|
46
|
+
for (const instance of instances) {
|
|
47
|
+
let methods = Reflect.getMetadata('smartdi:post-construct', instance);
|
|
48
|
+
if (!(methods === null || methods === void 0 ? void 0 : methods.length))
|
|
49
|
+
continue;
|
|
50
|
+
for (const method of methods) {
|
|
51
|
+
const result = instance[method]();
|
|
52
|
+
if (result instanceof Promise)
|
|
53
|
+
promises.push(result);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (!promises.length)
|
|
57
|
+
return;
|
|
58
|
+
yield Promise.all(promises);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
static uninitialize() {
|
|
62
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
63
|
+
const items = [...SmartDI[$singletons]].reverse();
|
|
64
|
+
const promises = [];
|
|
65
|
+
for (const item of items) {
|
|
66
|
+
const instance = item.instance;
|
|
67
|
+
if (!instance)
|
|
68
|
+
continue;
|
|
69
|
+
item.instance = undefined;
|
|
70
|
+
let methods = Reflect.getMetadata('smartdi:pre-destroy', instance);
|
|
71
|
+
if (!(methods === null || methods === void 0 ? void 0 : methods.length))
|
|
72
|
+
continue;
|
|
73
|
+
for (const method of methods) {
|
|
74
|
+
const result = instance[method]();
|
|
75
|
+
if (result instanceof Promise)
|
|
76
|
+
promises.push(result);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (!promises.length)
|
|
80
|
+
return;
|
|
81
|
+
yield Promise.all(promises);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
27
84
|
static internalGet(clue, creatings, ...args) {
|
|
28
85
|
let constructor, name;
|
|
29
86
|
if (typeof clue === 'function') {
|
|
@@ -36,14 +93,14 @@ class SmartDI {
|
|
|
36
93
|
}
|
|
37
94
|
let item = SmartDI[$registry][name];
|
|
38
95
|
if (!item && constructor)
|
|
39
|
-
item = SmartDI.
|
|
96
|
+
item = SmartDI.resolveOneByConstructor(constructor);
|
|
40
97
|
if (!item)
|
|
41
98
|
throw new Error(`Can not resolve injectable '${name}'!`);
|
|
42
99
|
return SmartDI.obtainInstance(item, creatings, ...args);
|
|
43
100
|
}
|
|
44
101
|
static internalGetArray(constructor, creatings, ...args) {
|
|
45
|
-
const items = SmartDI.
|
|
46
|
-
if (items.length
|
|
102
|
+
const items = SmartDI.resolveByConstructor(constructor);
|
|
103
|
+
if (items.length === 0)
|
|
47
104
|
throw new Error(`Can not resolve injectable '${constructor.name}'!`);
|
|
48
105
|
const instances = [];
|
|
49
106
|
for (const item of items)
|
|
@@ -53,7 +110,7 @@ class SmartDI {
|
|
|
53
110
|
static obtainInstance(item, creatings, ...args) {
|
|
54
111
|
if (item.instance)
|
|
55
112
|
return item.instance;
|
|
56
|
-
if (args.length
|
|
113
|
+
if (args.length === 0)
|
|
57
114
|
args = item.args;
|
|
58
115
|
const instance = new item.class(...args);
|
|
59
116
|
if (item.singleton)
|
|
@@ -64,13 +121,20 @@ class SmartDI {
|
|
|
64
121
|
if (!item.singleton && creatings.has(item.name))
|
|
65
122
|
throw new Error('Circular dependency detected!');
|
|
66
123
|
creatings.add(item.name);
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
124
|
+
try {
|
|
125
|
+
for (const prop of Reflect.ownKeys(injects))
|
|
126
|
+
instance[prop] = injects[prop].array
|
|
127
|
+
? SmartDI.internalGetArray(injects[prop].clue, creatings, ...injects[prop].args)
|
|
128
|
+
: SmartDI.internalGet(injects[prop].clue, creatings, ...injects[prop].args);
|
|
129
|
+
}
|
|
130
|
+
catch (e) {
|
|
131
|
+
if (item.singleton)
|
|
132
|
+
item.instance = undefined;
|
|
133
|
+
throw e;
|
|
134
|
+
}
|
|
71
135
|
return instance;
|
|
72
136
|
}
|
|
73
|
-
static
|
|
137
|
+
static resolveByConstructor(constructor) {
|
|
74
138
|
let matched = [];
|
|
75
139
|
function isSubclass(sub, sup) {
|
|
76
140
|
let proto = Object.getPrototypeOf(sub);
|
|
@@ -88,16 +152,17 @@ class SmartDI {
|
|
|
88
152
|
}
|
|
89
153
|
return matched;
|
|
90
154
|
}
|
|
91
|
-
static
|
|
92
|
-
const items = SmartDI.
|
|
155
|
+
static resolveOneByConstructor(constructor) {
|
|
156
|
+
const items = SmartDI.resolveByConstructor(constructor);
|
|
93
157
|
if (items.length > 1)
|
|
94
158
|
throw new Error(`Multiple injectable classes found for '${constructor.name}': ${items.map(item => item.name).join(', ')}`);
|
|
95
159
|
return items[0];
|
|
96
160
|
}
|
|
97
161
|
}
|
|
98
162
|
exports.SmartDI = SmartDI;
|
|
99
|
-
_a = $registry;
|
|
163
|
+
_a = $registry, _b = $singletons;
|
|
100
164
|
SmartDI[_a] = {};
|
|
165
|
+
SmartDI[_b] = [];
|
|
101
166
|
function Injectable(options) {
|
|
102
167
|
return (target) => {
|
|
103
168
|
SmartDI.register(target, options);
|
|
@@ -120,3 +185,19 @@ function InjectArray(clue, ...args) {
|
|
|
120
185
|
};
|
|
121
186
|
}
|
|
122
187
|
exports.InjectArray = InjectArray;
|
|
188
|
+
function PostConstruct() {
|
|
189
|
+
return function (target, key, _descriptor) {
|
|
190
|
+
let methods = Reflect.getMetadata('smartdi:post-construct', target) || [];
|
|
191
|
+
methods.push(key);
|
|
192
|
+
Reflect.defineMetadata('smartdi:post-construct', methods, target);
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
exports.PostConstruct = PostConstruct;
|
|
196
|
+
function PreDestroy() {
|
|
197
|
+
return function (target, key, _descriptor) {
|
|
198
|
+
let methods = Reflect.getMetadata('smartdi:pre-destroy', target) || [];
|
|
199
|
+
methods.push(key);
|
|
200
|
+
Reflect.defineMetadata('smartdi:pre-destroy', methods, target);
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
exports.PreDestroy = PreDestroy;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "smartdi",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "A simple dependency injector based on decorators.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"homepage": "https://github.com/iwares/smartdi#readme",
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@types/node": "^22.13.10",
|
|
31
|
-
"reflect-metadata": "^0.2.2"
|
|
31
|
+
"reflect-metadata": "^0.2.2",
|
|
32
|
+
"typescript": "^5.1.6"
|
|
32
33
|
}
|
|
33
|
-
}
|
|
34
|
+
}
|