@resolid/di 0.6.1 → 0.7.1
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 +2 -56
- package/dist/{index.d.ts → index.d.mts} +5 -55
- package/dist/index.mjs +1 -0
- package/package.json +25 -28
- package/dist/index.js +0 -1
package/README.md
CHANGED
|
@@ -17,7 +17,6 @@ and avoids circular dependency issues.
|
|
|
17
17
|
- Optional dependency resolution.
|
|
18
18
|
- Detects circular dependencies.
|
|
19
19
|
- Handles disposable instances with dispose() support.
|
|
20
|
-
- Fully async-compatible with inject() and injectAsync() functions.
|
|
21
20
|
- Context-aware injection with InjectionContext.
|
|
22
21
|
|
|
23
22
|
## Installation
|
|
@@ -95,58 +94,6 @@ container.add({
|
|
|
95
94
|
});
|
|
96
95
|
```
|
|
97
96
|
|
|
98
|
-
### Asynchronous Dependencies
|
|
99
|
-
|
|
100
|
-
```typescript
|
|
101
|
-
import { Container, injectAsync } from "@resolid/di";
|
|
102
|
-
|
|
103
|
-
class AsyncDatabaseService {
|
|
104
|
-
async connect(): Promise<void> {
|
|
105
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
106
|
-
console.log("Database connected");
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
class AsyncUserService {
|
|
111
|
-
private db: AsyncDatabaseService;
|
|
112
|
-
|
|
113
|
-
constructor(db: AsyncDatabaseService) {
|
|
114
|
-
this.db = db;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
async getUser(id: number): Promise<string> {
|
|
118
|
-
return `User ${id}`;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const container = new Container();
|
|
123
|
-
|
|
124
|
-
container.add({
|
|
125
|
-
token: AsyncDatabaseService,
|
|
126
|
-
factory: async () => {
|
|
127
|
-
const db = new AsyncDatabaseService();
|
|
128
|
-
await db.connect();
|
|
129
|
-
return db;
|
|
130
|
-
},
|
|
131
|
-
async: true,
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
container.add({
|
|
135
|
-
token: AsyncUserService,
|
|
136
|
-
factory: async () => {
|
|
137
|
-
const db = await injectAsync(AsyncDatabaseService);
|
|
138
|
-
return new AsyncUserService(db);
|
|
139
|
-
},
|
|
140
|
-
async: true,
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
// Resolve async services
|
|
144
|
-
const userService = await container.getAsync(AsyncUserService);
|
|
145
|
-
const user = await userService.getUser(1);
|
|
146
|
-
|
|
147
|
-
console.log(user); // Output: User 1
|
|
148
|
-
```
|
|
149
|
-
|
|
150
97
|
### Optional Dependencies
|
|
151
98
|
|
|
152
99
|
```typescript
|
|
@@ -255,11 +202,10 @@ const container = new Container();
|
|
|
255
202
|
|
|
256
203
|
container.add({
|
|
257
204
|
token: DatabaseConnection,
|
|
258
|
-
factory:
|
|
259
|
-
async: true,
|
|
205
|
+
factory: () => new DatabaseConnection(),
|
|
260
206
|
});
|
|
261
207
|
|
|
262
|
-
const db =
|
|
208
|
+
const db = container.get(DatabaseConnection);
|
|
263
209
|
|
|
264
210
|
// Dispose all singleton instances
|
|
265
211
|
await container.dispose(); // Output: Database connection closed
|
|
@@ -21,45 +21,21 @@ interface Resolver {
|
|
|
21
21
|
lazy?: boolean;
|
|
22
22
|
optional?: boolean;
|
|
23
23
|
}) => T | undefined | (() => T | undefined));
|
|
24
|
-
getAsync: (<T>(token: Token<T>) => Promise<T>) & (<T>(token: Token<T>, options: {
|
|
25
|
-
optional: true;
|
|
26
|
-
}) => Promise<T | undefined>) & (<T>(token: Token<T>, options: {
|
|
27
|
-
lazy: true;
|
|
28
|
-
}) => () => Promise<T>) & (<T>(token: Token<T>, options: {
|
|
29
|
-
lazy: true;
|
|
30
|
-
optional: true;
|
|
31
|
-
}) => () => Promise<T | undefined>) & (<T>(token: Token<T>, options: {
|
|
32
|
-
lazy?: false;
|
|
33
|
-
optional?: boolean;
|
|
34
|
-
}) => Promise<T | undefined>) & (<T>(token: Token<T>, options?: {
|
|
35
|
-
lazy?: boolean;
|
|
36
|
-
optional?: boolean;
|
|
37
|
-
}) => Promise<T | undefined> | (() => Promise<T | undefined>));
|
|
38
24
|
}
|
|
39
25
|
//#endregion
|
|
40
26
|
//#region src/container/index.d.ts
|
|
41
27
|
type Scope = "singleton" | "transient";
|
|
42
|
-
|
|
43
|
-
token: Token<T>;
|
|
44
|
-
factory: (resolver: Resolver) => T;
|
|
45
|
-
async?: false;
|
|
46
|
-
scope?: Scope;
|
|
47
|
-
};
|
|
48
|
-
type AsyncProvider<T = unknown> = {
|
|
28
|
+
interface Provider<T = unknown> {
|
|
49
29
|
token: Token<T>;
|
|
50
|
-
factory: (
|
|
51
|
-
async?: true;
|
|
30
|
+
factory: () => T;
|
|
52
31
|
scope?: Scope;
|
|
53
|
-
}
|
|
54
|
-
type Provider<T = unknown> = SyncProvider<T> | AsyncProvider<T>;
|
|
32
|
+
}
|
|
55
33
|
declare class Container implements Resolver, Disposable {
|
|
56
34
|
private readonly _providers;
|
|
57
35
|
private readonly _singletons;
|
|
58
36
|
private readonly _constructing;
|
|
59
37
|
private _checkCircularDependency;
|
|
60
|
-
private _resolveProvide;
|
|
61
38
|
private _resolve;
|
|
62
|
-
private _resolveAsync;
|
|
63
39
|
add(provider: Provider): void;
|
|
64
40
|
get<T>(token: Token<T>): T;
|
|
65
41
|
get<T>(token: Token<T>, options: {
|
|
@@ -73,24 +49,9 @@ declare class Container implements Resolver, Disposable {
|
|
|
73
49
|
optional: true;
|
|
74
50
|
}): () => T | undefined;
|
|
75
51
|
get<T>(token: Token<T>, options: {
|
|
76
|
-
lazy
|
|
52
|
+
lazy: false;
|
|
77
53
|
optional?: boolean;
|
|
78
54
|
}): T | undefined;
|
|
79
|
-
getAsync<T>(token: Token<T>): Promise<T>;
|
|
80
|
-
getAsync<T>(token: Token<T>, options: {
|
|
81
|
-
optional: true;
|
|
82
|
-
}): Promise<T | undefined>;
|
|
83
|
-
getAsync<T>(token: Token<T>, options: {
|
|
84
|
-
lazy: true;
|
|
85
|
-
}): () => Promise<T>;
|
|
86
|
-
getAsync<T>(token: Token<T>, options: {
|
|
87
|
-
lazy: true;
|
|
88
|
-
optional: true;
|
|
89
|
-
}): () => Promise<T | undefined>;
|
|
90
|
-
getAsync<T>(token: Token<T>, options: {
|
|
91
|
-
lazy?: false;
|
|
92
|
-
optional?: boolean;
|
|
93
|
-
}): Promise<T | undefined>;
|
|
94
55
|
dispose(): Promise<void>;
|
|
95
56
|
}
|
|
96
57
|
//#endregion
|
|
@@ -106,16 +67,5 @@ declare function inject<T>(token: Token<T>, options: {
|
|
|
106
67
|
lazy: true;
|
|
107
68
|
optional: true;
|
|
108
69
|
}): () => T | undefined;
|
|
109
|
-
declare function injectAsync<T>(token: Token<T>): Promise<T>;
|
|
110
|
-
declare function injectAsync<T>(token: Token<T>, options: {
|
|
111
|
-
optional: true;
|
|
112
|
-
}): Promise<T | undefined>;
|
|
113
|
-
declare function injectAsync<T>(token: Token<T>, options: {
|
|
114
|
-
lazy: true;
|
|
115
|
-
}): () => Promise<T>;
|
|
116
|
-
declare function injectAsync<T>(token: Token<T>, options: {
|
|
117
|
-
lazy: true;
|
|
118
|
-
optional: true;
|
|
119
|
-
}): () => Promise<T | undefined>;
|
|
120
70
|
//#endregion
|
|
121
|
-
export { Container, Provider,
|
|
71
|
+
export { Container, Provider, Scope, type Token, inject };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=class extends Error{constructor(){super(`inject() must be called within a injection context`)}},t=class t{static contextStack=[];resolver;constructor(e){this.resolver=e}static current(){let t=this.contextStack[this.contextStack.length-1];if(t===void 0)throw new e;return t}run(e){t.contextStack.push(this);try{return e(this.resolver)}finally{t.contextStack.pop()}}};function n(e){return typeof e==`symbol`?e.description??String(e):e.name}var r=class{_providers=new Map;_singletons=new Map;_constructing=[];_checkCircularDependency(e){if(this._constructing.includes(e))throw Error(`Circular dependency detected ${[...this._constructing,e].map(n).join(` -> `)}`)}_resolve(e,r){this._checkCircularDependency(e);let i=this._providers.get(e);if(i===void 0){if(!r)throw Error(`No provider found for ${n(e)}`);return}let a=i.scope!==`transient`;if(a&&this._singletons.has(e))return this._singletons.get(e);this._constructing.push(e);try{let n=new t(this).run(()=>i.factory());return a&&this._singletons.set(e,n),n}finally{this._constructing.pop()}}add(e){this._providers.set(e.token,e)}get(e,t){return t?.lazy??!1?()=>this.get(e,{...t,lazy:!1}):this._resolve(e,t?.optional??!1)}async dispose(){let e=0,t=``;for(let[r,i]of this._singletons)if(typeof i.dispose==`function`)try{await i.dispose()}catch(i){e++,t+=`${n(r)}: ${i instanceof Error?i.message:i}; `}if(this._singletons.clear(),e>0)throw Error(`Failed to dispose ${e} provider(s):\n${t.slice(0,-2)}`)}};function i(n,r){try{return t.current().run(e=>e.get(n,r))}catch(t){if(t instanceof e&&r?.optional==1)return;throw t}}export{r as Container,i as inject};
|
package/package.json
CHANGED
|
@@ -1,56 +1,53 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@resolid/di",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "TypeScript Dependency Injection Container",
|
|
6
6
|
"keywords": [
|
|
7
|
-
"resolid",
|
|
8
7
|
"container",
|
|
9
|
-
"
|
|
10
|
-
"inversion of control",
|
|
8
|
+
"dependency injection",
|
|
11
9
|
"di",
|
|
12
|
-
"
|
|
10
|
+
"inversion of control",
|
|
11
|
+
"ioc",
|
|
12
|
+
"resolid"
|
|
13
13
|
],
|
|
14
14
|
"homepage": "https://www.resolid.tech",
|
|
15
|
-
"repository": {
|
|
16
|
-
"type": "git",
|
|
17
|
-
"url": "git+https://github.com/resolid/framework.git",
|
|
18
|
-
"directory": "packages/di"
|
|
19
|
-
},
|
|
20
15
|
"license": "MIT",
|
|
21
16
|
"author": {
|
|
22
17
|
"name": "Huijie Wei",
|
|
23
18
|
"email": "hello@resolid.tech"
|
|
24
19
|
},
|
|
25
|
-
"
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
"
|
|
29
|
-
"types": "./dist/index.d.ts",
|
|
30
|
-
"import": "./dist/index.js"
|
|
31
|
-
}
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/resolid/framework.git",
|
|
23
|
+
"directory": "packages/di"
|
|
32
24
|
},
|
|
33
|
-
"main": "./dist/index.js",
|
|
34
|
-
"types": "./dist/index.d.ts",
|
|
35
25
|
"files": [
|
|
36
26
|
"dist"
|
|
37
27
|
],
|
|
38
|
-
"
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
"
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
28
|
+
"type": "module",
|
|
29
|
+
"sideEffects": false,
|
|
30
|
+
"types": "./dist/index.d.mts",
|
|
31
|
+
"exports": {
|
|
32
|
+
".": {
|
|
33
|
+
"types": "./dist/index.d.mts",
|
|
34
|
+
"import": "./dist/index.mjs"
|
|
35
|
+
}
|
|
46
36
|
},
|
|
47
37
|
"publishConfig": {
|
|
48
38
|
"access": "public",
|
|
49
39
|
"provenance": true
|
|
50
40
|
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"tsdown": "^0.20.3",
|
|
43
|
+
"typescript": "^5.9.3"
|
|
44
|
+
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": "^22.13.0 || >=24"
|
|
47
|
+
},
|
|
51
48
|
"scripts": {
|
|
52
49
|
"build": "tsdown",
|
|
53
|
-
"lint": "
|
|
50
|
+
"lint": "oxlint",
|
|
54
51
|
"test": "vitest run",
|
|
55
52
|
"typecheck": "tsc --noEmit"
|
|
56
53
|
}
|
package/dist/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
var e=class extends Error{constructor(){super(`inject() / injectAsync() must be called within a injection context`)}},t=class t{static contextStack=[];resolver;constructor(e){this.resolver=e}static current(){let t=this.contextStack[this.contextStack.length-1];if(t===void 0)throw new e;return t}run(e){t.contextStack.push(this);try{return e(this.resolver)}finally{t.contextStack.pop()}}async runAsync(e){t.contextStack.push(this);try{return await e(this.resolver)}finally{t.contextStack.pop()}}};function n(e){return typeof e==`symbol`?e.description??String(e):e.name}var r=class{_providers=new Map;_singletons=new Map;_constructing=[];_checkCircularDependency(e){if(this._constructing.includes(e))throw Error(`Circular dependency detected ${[...this._constructing,e].map(n).join(` -> `)}`)}_resolveProvide(e,t){let r=this._providers.get(e);if(r===void 0&&!t)throw Error(`No provider found for ${n(e)}`);return r}_resolve(e,r){this._checkCircularDependency(e);let i=this._resolveProvide(e,r);if(i===void 0)return;if(i.async)throw Error(`Provider for ${n(e)} is async, please use injectAsync()`);let a=i.scope!==`transient`;if(a&&this._singletons.has(e))return this._singletons.get(e);this._constructing.push(e);try{let n=new t(this).run(()=>i.factory(this));return a&&this._singletons.set(e,n),n}finally{this._constructing.pop()}}async _resolveAsync(e,n){this._checkCircularDependency(e);let r=this._resolveProvide(e,n);if(r===void 0)return;let i=r.scope!==`transient`;if(i&&this._singletons.has(e))return this._singletons.get(e);this._constructing.push(e);try{let n=await new t(this).runAsync(async()=>await r.factory(this));return i&&this._singletons.set(e,n),n}finally{this._constructing.pop()}}add(e){this._providers.set(e.token,e)}get(e,t){return t?.lazy??!1?()=>this.get(e,{...t,lazy:!1}):this._resolve(e,t?.optional??!1)}getAsync(e,t){return t?.lazy??!1?()=>this.getAsync(e,{...t,lazy:!1}):this._resolveAsync(e,t?.optional??!1)}async dispose(){let e=0,t=``;for(let[r,i]of this._singletons)if(typeof i.dispose==`function`)try{await i.dispose()}catch(i){e++,t+=`${n(r)}: ${i instanceof Error?i.message:i}; `}if(this._singletons.clear(),e>0)throw Error(`Failed to dispose ${e} provider(s):\n${t.slice(0,-2)}`)}};function i(n,r){try{return t.current().run(e=>e.get(n,r))}catch(t){if(t instanceof e&&r?.optional==1)return;throw t}}function a(n,r){try{return r?.lazy?t.current().run(e=>e.getAsync(n,{...r,lazy:!0})):t.current().runAsync(e=>e.getAsync(n,{...r,lazy:!1}))}catch(t){return t instanceof e&&r?.optional===!0?r?.lazy?()=>Promise.resolve(void 0):Promise.resolve(void 0):Promise.reject(t)}}export{r as Container,i as inject,a as injectAsync};
|