@fluojs/di 1.0.0-beta.1 → 1.0.0-beta.2
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.ko.md +4 -0
- package/README.md +4 -0
- package/dist/container.d.ts.map +1 -1
- package/dist/container.js +35 -1
- package/package.json +1 -1
package/README.ko.md
CHANGED
|
@@ -83,6 +83,10 @@ const requestContainer = container.createRequestScope();
|
|
|
83
83
|
const scopedService = await requestContainer.resolve(RequestScopedService);
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
+
request scope 컨테이너는 부모 체인의 provider를 해석할 수 있지만, request가 소유하는 등록은 새 singleton provider를 만들 수 없습니다. singleton provider는 request scope를 만들기 전에 루트 컨테이너에 등록하세요. request scope에 로컬 provider를 추가해야 한다면 `scope: 'request'`/`Scope.REQUEST`를 명시하거나 `override()`로 의도적인 request-local 교체를 표현하세요. multi provider에도 같은 규칙이 적용됩니다. 기본 scope의 multi provider는 루트 컨테이너에 등록하고, request-local multi provider는 request scope를 명시하거나 `override()`로 교체해야 합니다.
|
|
87
|
+
|
|
88
|
+
provider 객체는 등록 시점에 검증됩니다. 모든 객체 provider는 null이 아닌 `provide` 토큰과 정확히 하나의 전략(`useClass`, `useValue`, `useFactory`, `useExisting`)을 포함해야 합니다. 잘못된 provider 형태는 컨테이너 그래프에 영향을 주기 전에 `InvalidProviderError`를 발생시킵니다.
|
|
89
|
+
|
|
86
90
|
## 순환 의존성 처리
|
|
87
91
|
|
|
88
92
|
컨테이너는 순환 의존성을 자동으로 감지하고 `CircularDependencyError`를 발생시켜 무한 루프를 방지합니다. 여기에는 직접 참조(A→A), 이중 노드(A→B→A), 깊은 순환(A→B→C→A)이 모두 포함됩니다.
|
package/README.md
CHANGED
|
@@ -83,6 +83,10 @@ const requestContainer = container.createRequestScope();
|
|
|
83
83
|
const scopedService = await requestContainer.resolve(RequestScopedService);
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
+
Request-scope containers may resolve providers from their parent chain, but request-owned registrations must not introduce new singleton providers. Register singleton providers on the root container before creating request scopes. If a request scope needs local additions, declare them with `scope: 'request'`/`Scope.REQUEST` or use `override()` for an explicit request-local replacement. The same rule applies to multi providers: default-scope multi providers belong on the root container, while request-local multi providers must opt into request scope or be replaced through `override()`.
|
|
87
|
+
|
|
88
|
+
Provider objects are validated at registration time: every object provider must include a non-null `provide` token and exactly one strategy (`useClass`, `useValue`, `useFactory`, or `useExisting`). Invalid provider shapes throw `InvalidProviderError` before they can affect the container graph.
|
|
89
|
+
|
|
86
90
|
## Circular Dependency Handling
|
|
87
91
|
|
|
88
92
|
The container automatically detects circular dependencies and throws a `CircularDependencyError` to prevent infinite loops. This includes direct (A→A), two-node (A→B→A), and deep (A→B→C→A) cycles.
|
package/dist/container.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmC,KAAK,KAAK,EAAE,MAAM,cAAc,CAAC;AAW3E,OAAO,KAAK,EASV,QAAQ,EAET,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmC,KAAK,KAAK,EAAE,MAAM,cAAc,CAAC;AAW3E,OAAO,KAAK,EASV,QAAQ,EAET,MAAM,YAAY,CAAC;AAuIpB;;GAEG;AACH,qBAAa,SAAS;IAelB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IACxB,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IAftC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAwC;IACtE,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAA0C;IAC7E,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAoB;IAC1D,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAsC;IACnE,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAmD;IACrF,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAmD;IACvF,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAA4B;IAC/D,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAiB;IACrD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA+B;IAC9D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAwB;IACpD,OAAO,CAAC,cAAc,CAA4B;IAClD,OAAO,CAAC,QAAQ,CAAS;gBAGN,MAAM,CAAC,EAAE,SAAS,YAAA,EAClB,mBAAmB,UAAQ,EAC5C,cAAc,CAAC,EAAE,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAK/C;;;;;;;;;OASG;IACH,QAAQ,CAAC,GAAG,SAAS,EAAE,QAAQ,EAAE,GAAG,IAAI;IAyCxC;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,GAAG,SAAS,EAAE,QAAQ,EAAE,GAAG,IAAI;IA6BxC;;;;;OAKG;IACH,GAAG,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO;IAI1B;;;;;OAKG;IACH,kBAAkB,IAAI,SAAS;IAa/B;;;;;;;;;OASG;IACG,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAW7C;;;;;OAKG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;YAiBhB,UAAU;IAgBxB,OAAO,CAAC,QAAQ;IAMhB,OAAO,CAAC,4BAA4B;IAsBpC,OAAO,CAAC,6BAA6B;IAIrC,OAAO,CAAC,qBAAqB;IAM7B,OAAO,CAAC,4BAA4B;IAIpC,OAAO,CAAC,oBAAoB;IAM5B,OAAO,CAAC,qBAAqB;YAgBf,gBAAgB;YAehB,8BAA8B;IA+B5C,OAAO,CAAC,eAAe;YAgBT,kBAAkB;IAMhC,OAAO,CAAC,mCAAmC;YAoB7B,6BAA6B;YAc7B,4BAA4B;IA4B1C,OAAO,CAAC,6BAA6B;YAQvB,gCAAgC;IAuB9C,OAAO,CAAC,qBAAqB;IAI7B,OAAO,CAAC,kCAAkC;YAI5B,eAAe;YAwBf,gBAAgB;IAiB9B,OAAO,CAAC,IAAI;IAIZ,OAAO,CAAC,cAAc;IAUtB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,QAAQ;IAuBhB,OAAO,CAAC,aAAa;IAuBrB,OAAO,CAAC,qBAAqB;IAI7B,OAAO,CAAC,oBAAoB;YAkBd,YAAY;YAaZ,0BAA0B;YA0B1B,8BAA8B;IAc5C,OAAO,CAAC,mBAAmB;YAWb,yBAAyB;IAMvC,OAAO,CAAC,qBAAqB;IAoB7B,OAAO,CAAC,mBAAmB;IAU3B,OAAO,CAAC,YAAY;YAIN,WAAW;IA+BzB,OAAO,CAAC,+BAA+B;IAsBvC,OAAO,CAAC,wBAAwB;IA6BhC,OAAO,CAAC,8BAA8B;YAYxB,mBAAmB;IAUjC,OAAO,CAAC,qBAAqB;CA6C9B"}
|
package/dist/container.js
CHANGED
|
@@ -17,6 +17,21 @@ function isClassProvider(value) {
|
|
|
17
17
|
function isExistingProvider(value) {
|
|
18
18
|
return typeof value === 'object' && value !== null && 'useExisting' in value;
|
|
19
19
|
}
|
|
20
|
+
function assertProviderToken(provider) {
|
|
21
|
+
if (!('provide' in provider) || provider.provide == null) {
|
|
22
|
+
throw new InvalidProviderError('Provider object must include a non-null provide token.');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function assertProviderStrategy(provider) {
|
|
26
|
+
const strategyCount = Number('useValue' in provider) + Number('useFactory' in provider) + Number('useClass' in provider) + Number('useExisting' in provider);
|
|
27
|
+
if (strategyCount !== 1) {
|
|
28
|
+
throw new InvalidProviderError('Provider object must declare exactly one of useValue, useFactory, useClass, or useExisting.');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function assertObjectProvider(provider) {
|
|
32
|
+
assertProviderToken(provider);
|
|
33
|
+
assertProviderStrategy(provider);
|
|
34
|
+
}
|
|
20
35
|
function normalizeInjectToken(token) {
|
|
21
36
|
if (token == null) {
|
|
22
37
|
throw new InvalidProviderError('Inject token must not be null or undefined. Check that all tokens in @Inject(...) are defined at the point of decoration (forward-reference cycles require forwardRef()).');
|
|
@@ -35,6 +50,7 @@ function normalizeProvider(provider) {
|
|
|
35
50
|
};
|
|
36
51
|
}
|
|
37
52
|
if (isValueProvider(provider)) {
|
|
53
|
+
assertObjectProvider(provider);
|
|
38
54
|
return {
|
|
39
55
|
inject: [],
|
|
40
56
|
multi: provider.multi,
|
|
@@ -45,6 +61,12 @@ function normalizeProvider(provider) {
|
|
|
45
61
|
};
|
|
46
62
|
}
|
|
47
63
|
if (isFactoryProvider(provider)) {
|
|
64
|
+
assertObjectProvider(provider);
|
|
65
|
+
if (typeof provider.useFactory !== 'function') {
|
|
66
|
+
throw new InvalidProviderError('Factory provider useFactory must be a function.', {
|
|
67
|
+
token: provider.provide
|
|
68
|
+
});
|
|
69
|
+
}
|
|
48
70
|
const metadata = provider.resolverClass ? getClassDiMetadata(provider.resolverClass) : undefined;
|
|
49
71
|
return {
|
|
50
72
|
inject: (provider.inject ?? []).map(normalizeInjectToken),
|
|
@@ -56,6 +78,12 @@ function normalizeProvider(provider) {
|
|
|
56
78
|
};
|
|
57
79
|
}
|
|
58
80
|
if (isClassProvider(provider)) {
|
|
81
|
+
assertObjectProvider(provider);
|
|
82
|
+
if (typeof provider.useClass !== 'function') {
|
|
83
|
+
throw new InvalidProviderError('Class provider useClass must be a constructor.', {
|
|
84
|
+
token: provider.provide
|
|
85
|
+
});
|
|
86
|
+
}
|
|
59
87
|
const metadata = getClassDiMetadata(provider.useClass);
|
|
60
88
|
return {
|
|
61
89
|
inject: (provider.inject ?? metadata?.inject ?? []).map(normalizeInjectToken),
|
|
@@ -67,6 +95,12 @@ function normalizeProvider(provider) {
|
|
|
67
95
|
};
|
|
68
96
|
}
|
|
69
97
|
if (isExistingProvider(provider)) {
|
|
98
|
+
assertObjectProvider(provider);
|
|
99
|
+
if (provider.useExisting == null) {
|
|
100
|
+
throw new InvalidProviderError('Alias provider useExisting must be a non-null token.', {
|
|
101
|
+
token: provider.provide
|
|
102
|
+
});
|
|
103
|
+
}
|
|
70
104
|
return {
|
|
71
105
|
inject: [],
|
|
72
106
|
provide: provider.provide,
|
|
@@ -118,7 +152,7 @@ export class Container {
|
|
|
118
152
|
}
|
|
119
153
|
for (const provider of providers) {
|
|
120
154
|
const normalized = normalizeProvider(provider);
|
|
121
|
-
if (this.requestScopeEnabled && normalized.scope === Scope.DEFAULT
|
|
155
|
+
if (this.requestScopeEnabled && normalized.scope === Scope.DEFAULT) {
|
|
122
156
|
throw new ScopeMismatchError(`Singleton provider ${String(normalized.provide)} cannot be registered on a request-scope container.`, {
|
|
123
157
|
token: normalized.provide,
|
|
124
158
|
scope: 'singleton',
|