@fougere/container 0.8.3-alpha.0 → 0.9.0-alpha.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/dist/container.d.ts +15 -14
- package/dist/container.d.ts.map +1 -1
- package/dist/create.d.ts.map +1 -1
- package/dist/create.js +14 -19
- package/dist/create.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/container.ts +16 -14
- package/src/create.ts +14 -19
- package/src/index.ts +1 -2
package/dist/container.d.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A class constructor with any arguments.
|
|
3
|
-
*/
|
|
4
1
|
export type Constructor<T = unknown> = new (...args: any[]) => T;
|
|
5
|
-
/**
|
|
6
|
-
* Registration options.
|
|
7
|
-
*/
|
|
8
2
|
export interface RegisterOptions {
|
|
9
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* `'singleton'` builds once per scope and the container disposes it; `'transient'`
|
|
5
|
+
* builds per `resolve` and the caller closes it. Absent means `'transient'`.
|
|
6
|
+
*/
|
|
10
7
|
lifetime?: 'singleton' | 'transient';
|
|
11
|
-
/**
|
|
8
|
+
/**
|
|
9
|
+
* The TYPE names of the constructor's parameters, resolved in this scope in order —
|
|
10
|
+
* `constructor(private users: UserRepository, private log: Logger)` is
|
|
11
|
+
* `deps: ['UserRepository', 'Logger']`.
|
|
12
|
+
*/
|
|
12
13
|
deps?: string[];
|
|
13
14
|
}
|
|
14
15
|
/** Anything holding a resource can say so, and disposing the container says it back. */
|
|
@@ -17,19 +18,19 @@ export interface Disposable {
|
|
|
17
18
|
}
|
|
18
19
|
/** DI container interface — the only thing application code sees. */
|
|
19
20
|
export interface Container {
|
|
20
|
-
/**
|
|
21
|
+
/** The container builds it: `register('UserService', UserService, { deps: ['UserRepository'] })`. */
|
|
21
22
|
register<T>(name: string, ctor: Constructor<T>, options?: RegisterOptions): void;
|
|
22
|
-
/**
|
|
23
|
+
/** Already built, so never disposed here — `registerValue('Logger', new Logger('app'))`, a scope, a config. */
|
|
23
24
|
registerValue<T>(name: string, value: T): void;
|
|
24
|
-
/**
|
|
25
|
+
/** Throws when nothing answers the name; `has` asks without throwing. */
|
|
25
26
|
resolve<T>(name: string): T;
|
|
26
|
-
/**
|
|
27
|
+
/** Answers for this scope and its parents, and builds nothing. */
|
|
27
28
|
has(name: string): boolean;
|
|
28
29
|
/** A resolver of last resort, consulted when no scope holds the name. */
|
|
29
30
|
setFallback?(resolve: (name: string) => unknown): void;
|
|
30
|
-
/**
|
|
31
|
+
/** The child reads every registration above it; the parent closes it. */
|
|
31
32
|
createScope(): Container;
|
|
32
|
-
/**
|
|
33
|
+
/** Children first, then what this scope built, in reverse — refusals travel as one `AggregateError`. */
|
|
33
34
|
dispose(): Promise<void>;
|
|
34
35
|
}
|
|
35
36
|
//# sourceMappingURL=container.d.ts.map
|
package/dist/container.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":"AACA,MAAM,MAAM,WAAW,CAAC,CAAC,GAAG,OAAO,IAAI,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;AAEjE,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,QAAQ,CAAC,EAAE,WAAW,GAAG,WAAW,CAAC;IAErC;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,wFAAwF;AACxF,MAAM,WAAW,UAAU;IACzB,OAAO,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC;AAED,qEAAqE;AACrE,MAAM,WAAW,SAAS;IACxB,qGAAqG;IACrG,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IAEjF,+GAA+G;IAC/G,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IAE/C,yEAAyE;IACzE,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,CAAC;IAE5B,kEAAkE;IAClE,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAE3B,yEAAyE;IACzE,WAAW,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,GAAG,IAAI,CAAC;IAEvD,yEAAyE;IACzE,WAAW,IAAI,SAAS,CAAC;IAEzB,wGAAwG;IACxG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B"}
|
package/dist/create.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../src/create.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAA4C,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../src/create.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAA4C,MAAM,gBAAgB,CAAC;AA4I1F,wBAAgB,eAAe,IAAI,SAAS,CAE3C"}
|
package/dist/create.js
CHANGED
|
@@ -2,14 +2,11 @@ const isDisposable = (value) => typeof value === 'object' && value !== null &&
|
|
|
2
2
|
typeof value.dispose === 'function';
|
|
3
3
|
function createScope(parent) {
|
|
4
4
|
const registry = new Map();
|
|
5
|
-
//
|
|
6
|
-
//
|
|
5
|
+
// In construction order: a thing built later may hold one built earlier, so disposal
|
|
6
|
+
// walks this backwards.
|
|
7
7
|
const built = [];
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
// built while the parent holds nothing of its. Without this a frond's scope, which is
|
|
11
|
-
// where every provider lives, was never disposed at all: it is registered as a VALUE
|
|
12
|
-
// under `frond:<name>`, and a value is not the container's to dispose.
|
|
8
|
+
// Closed by this container, and before `built` — a child may hold what this scope built,
|
|
9
|
+
// never the other way round.
|
|
13
10
|
const children = [];
|
|
14
11
|
let fallback;
|
|
15
12
|
const remember = (value) => {
|
|
@@ -36,8 +33,8 @@ function createScope(parent) {
|
|
|
36
33
|
if (!entry && parent && parent._getEntry(name)) {
|
|
37
34
|
return parent.resolve(name);
|
|
38
35
|
}
|
|
39
|
-
// Nobody holds it.
|
|
40
|
-
//
|
|
36
|
+
// Nobody holds it. A frond declared in `remotes` registers nothing here, so its
|
|
37
|
+
// façade is fabricated by the fallback rather than found.
|
|
41
38
|
if (!entry) {
|
|
42
39
|
const made = container._getFallback()?.(name);
|
|
43
40
|
if (made !== undefined) {
|
|
@@ -49,9 +46,8 @@ function createScope(parent) {
|
|
|
49
46
|
if (entry.instance !== undefined)
|
|
50
47
|
return entry.instance;
|
|
51
48
|
const value = entry.factory(container);
|
|
52
|
-
// The container disposes what it KEEPS
|
|
53
|
-
//
|
|
54
|
-
// once per call, and its caller is the one who knows when it is done.
|
|
49
|
+
// The container disposes what it KEEPS: a transient is handed over and forgotten,
|
|
50
|
+
// and its caller is the one who knows when it is done.
|
|
55
51
|
if (entry.lifetime === 'singleton') {
|
|
56
52
|
entry.instance = value;
|
|
57
53
|
remember(value);
|
|
@@ -67,15 +63,14 @@ function createScope(parent) {
|
|
|
67
63
|
return child;
|
|
68
64
|
},
|
|
69
65
|
async dispose() {
|
|
70
|
-
//
|
|
71
|
-
//
|
|
72
|
-
//
|
|
73
|
-
// makes that reference garbage. Nothing created a scope at RUN time until frames did,
|
|
74
|
-
// so the list only ever grew at boot and stayed bounded — one per request, or one per
|
|
75
|
-
// transaction, and it grows for the life of the process.
|
|
66
|
+
// Everything is told before anything throws, then the failures travel together.
|
|
67
|
+
// Dropped from the parent first: a scope that closes itself leaves a reference the
|
|
68
|
+
// parent would hold for the life of the process.
|
|
76
69
|
parent?._forget(container);
|
|
77
70
|
const failures = [];
|
|
78
|
-
|
|
71
|
+
// A copy: closing a child splices it out of `children`, so walking the array
|
|
72
|
+
// itself stepped over every second sibling.
|
|
73
|
+
for (const child of [...children].reverse()) {
|
|
79
74
|
try {
|
|
80
75
|
await child.dispose();
|
|
81
76
|
}
|
package/dist/create.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.js","sourceRoot":"","sources":["../src/create.ts"],"names":[],"mappings":"AAcA,MAAM,YAAY,GAAG,CAAC,KAAc,EAAuB,EAAE,CAC3D,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;IAC3C,OAAQ,KAAoB,CAAC,OAAO,KAAK,UAAU,CAAC;AAEtD,SAAS,WAAW,CAAC,MAAuB;IAC1C,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAiB,CAAC;IAC1C,
|
|
1
|
+
{"version":3,"file":"create.js","sourceRoot":"","sources":["../src/create.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,SAAS,EACd,KAAK,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,SAAS,EACd,KAAK,WAAW,GACjB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC"}
|
package/package.json
CHANGED
package/src/container.ts
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A class constructor with any arguments.
|
|
3
|
-
*/
|
|
4
1
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5
2
|
export type Constructor<T = unknown> = new (...args: any[]) => T;
|
|
6
3
|
|
|
7
|
-
/**
|
|
8
|
-
* Registration options.
|
|
9
|
-
*/
|
|
10
4
|
export interface RegisterOptions {
|
|
11
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* `'singleton'` builds once per scope and the container disposes it; `'transient'`
|
|
7
|
+
* builds per `resolve` and the caller closes it. Absent means `'transient'`.
|
|
8
|
+
*/
|
|
12
9
|
lifetime?: 'singleton' | 'transient';
|
|
13
|
-
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The TYPE names of the constructor's parameters, resolved in this scope in order —
|
|
13
|
+
* `constructor(private users: UserRepository, private log: Logger)` is
|
|
14
|
+
* `deps: ['UserRepository', 'Logger']`.
|
|
15
|
+
*/
|
|
14
16
|
deps?: string[];
|
|
15
17
|
}
|
|
16
18
|
|
|
@@ -21,24 +23,24 @@ export interface Disposable {
|
|
|
21
23
|
|
|
22
24
|
/** DI container interface — the only thing application code sees. */
|
|
23
25
|
export interface Container {
|
|
24
|
-
/**
|
|
26
|
+
/** The container builds it: `register('UserService', UserService, { deps: ['UserRepository'] })`. */
|
|
25
27
|
register<T>(name: string, ctor: Constructor<T>, options?: RegisterOptions): void;
|
|
26
28
|
|
|
27
|
-
/**
|
|
29
|
+
/** Already built, so never disposed here — `registerValue('Logger', new Logger('app'))`, a scope, a config. */
|
|
28
30
|
registerValue<T>(name: string, value: T): void;
|
|
29
31
|
|
|
30
|
-
/**
|
|
32
|
+
/** Throws when nothing answers the name; `has` asks without throwing. */
|
|
31
33
|
resolve<T>(name: string): T;
|
|
32
34
|
|
|
33
|
-
/**
|
|
35
|
+
/** Answers for this scope and its parents, and builds nothing. */
|
|
34
36
|
has(name: string): boolean;
|
|
35
37
|
|
|
36
38
|
/** A resolver of last resort, consulted when no scope holds the name. */
|
|
37
39
|
setFallback?(resolve: (name: string) => unknown): void;
|
|
38
40
|
|
|
39
|
-
/**
|
|
41
|
+
/** The child reads every registration above it; the parent closes it. */
|
|
40
42
|
createScope(): Container;
|
|
41
43
|
|
|
42
|
-
/**
|
|
44
|
+
/** Children first, then what this scope built, in reverse — refusals travel as one `AggregateError`. */
|
|
43
45
|
dispose(): Promise<void>;
|
|
44
46
|
}
|
package/src/create.ts
CHANGED
|
@@ -18,14 +18,11 @@ const isDisposable = (value: unknown): value is Disposable =>
|
|
|
18
18
|
|
|
19
19
|
function createScope(parent?: ScopeContainer): ScopeContainer {
|
|
20
20
|
const registry = new Map<string, Entry>();
|
|
21
|
-
//
|
|
22
|
-
//
|
|
21
|
+
// In construction order: a thing built later may hold one built earlier, so disposal
|
|
22
|
+
// walks this backwards.
|
|
23
23
|
const built: unknown[] = [];
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
// built while the parent holds nothing of its. Without this a frond's scope, which is
|
|
27
|
-
// where every provider lives, was never disposed at all: it is registered as a VALUE
|
|
28
|
-
// under `frond:<name>`, and a value is not the container's to dispose.
|
|
24
|
+
// Closed by this container, and before `built` — a child may hold what this scope built,
|
|
25
|
+
// never the other way round.
|
|
29
26
|
const children: ScopeContainer[] = [];
|
|
30
27
|
let fallback: ((name: string) => unknown) | undefined;
|
|
31
28
|
|
|
@@ -57,8 +54,8 @@ function createScope(parent?: ScopeContainer): ScopeContainer {
|
|
|
57
54
|
return parent.resolve<T>(name);
|
|
58
55
|
}
|
|
59
56
|
|
|
60
|
-
// Nobody holds it.
|
|
61
|
-
//
|
|
57
|
+
// Nobody holds it. A frond declared in `remotes` registers nothing here, so its
|
|
58
|
+
// façade is fabricated by the fallback rather than found.
|
|
62
59
|
if (!entry) {
|
|
63
60
|
const made = container._getFallback()?.(name);
|
|
64
61
|
if (made !== undefined) {
|
|
@@ -70,9 +67,8 @@ function createScope(parent?: ScopeContainer): ScopeContainer {
|
|
|
70
67
|
|
|
71
68
|
if (entry.instance !== undefined) return entry.instance as T;
|
|
72
69
|
const value = entry.factory(container) as T;
|
|
73
|
-
// The container disposes what it KEEPS
|
|
74
|
-
//
|
|
75
|
-
// once per call, and its caller is the one who knows when it is done.
|
|
70
|
+
// The container disposes what it KEEPS: a transient is handed over and forgotten,
|
|
71
|
+
// and its caller is the one who knows when it is done.
|
|
76
72
|
if (entry.lifetime === 'singleton') {
|
|
77
73
|
entry.instance = value;
|
|
78
74
|
remember(value);
|
|
@@ -91,15 +87,14 @@ function createScope(parent?: ScopeContainer): ScopeContainer {
|
|
|
91
87
|
},
|
|
92
88
|
|
|
93
89
|
async dispose(): Promise<void> {
|
|
94
|
-
//
|
|
95
|
-
//
|
|
96
|
-
//
|
|
97
|
-
// makes that reference garbage. Nothing created a scope at RUN time until frames did,
|
|
98
|
-
// so the list only ever grew at boot and stayed bounded — one per request, or one per
|
|
99
|
-
// transaction, and it grows for the life of the process.
|
|
90
|
+
// Everything is told before anything throws, then the failures travel together.
|
|
91
|
+
// Dropped from the parent first: a scope that closes itself leaves a reference the
|
|
92
|
+
// parent would hold for the life of the process.
|
|
100
93
|
parent?._forget(container);
|
|
101
94
|
const failures: unknown[] = [];
|
|
102
|
-
|
|
95
|
+
// A copy: closing a child splices it out of `children`, so walking the array
|
|
96
|
+
// itself stepped over every second sibling.
|
|
97
|
+
for (const child of [...children].reverse()) {
|
|
103
98
|
try {
|
|
104
99
|
await child.dispose();
|
|
105
100
|
} catch (error) {
|