@fougere/container 0.9.0-alpha.1 → 0.9.2-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/README.md +79 -0
- package/dist/create.d.ts.map +1 -1
- package/dist/create.js +27 -8
- package/dist/create.js.map +1 -1
- package/package.json +1 -1
- package/src/create.ts +33 -8
package/README.md
CHANGED
|
@@ -13,6 +13,85 @@ that lives in another process.
|
|
|
13
13
|
pnpm add @fougere/container
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
## What the alternatives ask of a class
|
|
17
|
+
|
|
18
|
+
Measured at the tarball on 2026-09-11, not read off a README.
|
|
19
|
+
|
|
20
|
+
| | where a dependency is declared | what the class carries | deps | unpacked |
|
|
21
|
+
|---|---|---|---|---|
|
|
22
|
+
| [InversifyJS 8.2.3](https://www.npmjs.com/package/inversify) | a decorator | `@injectable()`, `@inject(TOKEN)` | 3 | 36 KB, plus its three |
|
|
23
|
+
| [tsyringe 4.10.0](https://www.npmjs.com/package/tsyringe) | a decorator, read through `Reflect` | `@injectable()`, and `import 'reflect-metadata'` at the entry point — it throws at load without one | `tslib` | 148 KB |
|
|
24
|
+
| [TypeDI 0.10.0](https://www.npmjs.com/package/typedi) | a decorator | `@Service()` | 0 | last published 2022-12-09 |
|
|
25
|
+
| [typed-inject 5.0.0](https://www.npmjs.com/package/typed-inject) | a static field | `static inject = tokens('logger')` | 0 | 102 KB |
|
|
26
|
+
| [Awilix 13.0.5](https://www.npmjs.com/package/awilix) | the parameter's NAME (`CLASSIC`), or the destructured property's (`PROXY`) | nothing — but the name becomes the contract | `fast-glob` | 326 KB |
|
|
27
|
+
| [didi 11.0.0](https://www.npmjs.com/package/didi) | the parameter's name, or `Car.$inject = ['engine']` | nothing, or the static | 0 | 49 KB |
|
|
28
|
+
| `@fougere/container` | the parameter's TYPE | nothing | 0 | 220 lines |
|
|
29
|
+
|
|
30
|
+
Every row but the last makes the class name the container. `@injectable()`, `static inject`
|
|
31
|
+
and `$inject` are the dependency written a second time, next to the signature that already
|
|
32
|
+
states it. A parameter name is the same thing spelled shorter, and it is the one a bundler
|
|
33
|
+
may rewrite — which is why didi ships `$inject` as the "minification safe manner", and why
|
|
34
|
+
`ProviderEntry.name` is written down here rather than read off `ctor.name` at boot.
|
|
35
|
+
|
|
36
|
+
Here the signature IS the declaration. `constructor(private users: UserRepository)` is read
|
|
37
|
+
by the scan (`depKeyOf`, `@fougere/compiler`), which hands the boot `deps:
|
|
38
|
+
['UserRepository']`. So `register` receives the graph already resolved and this container
|
|
39
|
+
infers nothing — which is the whole reason it fits in 220 lines. What these libraries exist
|
|
40
|
+
to answer is answered before they would run.
|
|
41
|
+
|
|
42
|
+
## What they have that this does not
|
|
43
|
+
|
|
44
|
+
- **typed-inject** resolves type-safely — `resolve<Token extends keyof TContext>` refuses at
|
|
45
|
+
compile time a token the injector cannot answer. Here `resolve<T>(name: string): T` is an
|
|
46
|
+
unchecked cast, and a wrong name is a boot error instead.
|
|
47
|
+
- **Awilix** has a third lifetime (`SCOPED`, one instance per scope), `aliasTo`, a disposer
|
|
48
|
+
per registration, and `loadModules`. This has two lifetimes, and disposes what it built.
|
|
49
|
+
|
|
50
|
+
And one thing none of them has: a resolver of last resort. `setFallback` has a single
|
|
51
|
+
caller — the boot, fabricating a façade for a frond declared in `remotes:`. Such a frond
|
|
52
|
+
registers nothing here, because it runs in another process.
|
|
53
|
+
|
|
54
|
+
## This one, measured the same way
|
|
55
|
+
|
|
56
|
+
`0.8.4-alpha.0` — 21 KB unpacked, zero dependencies, 220 lines, one test file. Seven
|
|
57
|
+
methods, two lifetimes, a parent chain consulted upward on every miss.
|
|
58
|
+
|
|
59
|
+
The holes, probed rather than assumed:
|
|
60
|
+
|
|
61
|
+
- **A transient is never disposed**, deliberately — the container disposes what it KEEPS and
|
|
62
|
+
hands a transient over. Nothing says so where it is registered.
|
|
63
|
+
- **A second `register` of one name overwrites, silently.** `Bundle` refuses a duplicate
|
|
64
|
+
registration key, `serveRpc` a second reading, `portBindings` two implementations of a
|
|
65
|
+
port. This does not.
|
|
66
|
+
- `RegisterOptions` and `Disposable` are named by `Container` but not exported from the
|
|
67
|
+
entry, so a caller cannot spell the options object it passes.
|
|
68
|
+
|
|
69
|
+
## Why not didi
|
|
70
|
+
|
|
71
|
+
It is the closest of the six, so it gets the measurement rather than a position.
|
|
72
|
+
`annotate(['engine', 'license'], Car)` puts the dependency list OUTSIDE the class — exactly
|
|
73
|
+
the shape the scan produces, and the class carries nothing, as here. `createChild` nests.
|
|
74
|
+
`get(name, false)` answers `null` instead of throwing. 49 KB, zero dependencies, published
|
|
75
|
+
2025-12-11.
|
|
76
|
+
|
|
77
|
+
Two things stop it. **It has no disposal at all** — no `dispose`, `teardown`, `destroy` or
|
|
78
|
+
`close`, in its API, its code or its README — and `container.dispose()` is the middle of the
|
|
79
|
+
three levels `app.dispose()` runs in reverse of construction. And its unit is a
|
|
80
|
+
`ModuleDeclaration` carrying `__init__`, `__depends__` and `__exports__`: a second notion of
|
|
81
|
+
module beside the frond, onto which every frond would have to be projected.
|
|
82
|
+
|
|
83
|
+
Reading it paid anyway. Its `currentlyResolving` stack is the shape used here, and naming
|
|
84
|
+
the descent in EVERY refusal — not only in a cycle — is its idea: `'Zzz' is not registered
|
|
85
|
+
(resolving: A → B → Zzz)`. Two things were changed on the way in. Its `pop()` sits outside a
|
|
86
|
+
`finally` (didi 11.0.0, `dist/index.js`), so a constructor that throws leaves the name on the
|
|
87
|
+
stack and the next resolution of it reports a cycle that is not there — measured, and the
|
|
88
|
+
reason this one pops in a `finally`. And its stack belongs to one injector, where this one
|
|
89
|
+
shares it down the tree, which is what lets a path that continues in a parent be named whole.
|
|
90
|
+
|
|
91
|
+
The day this container needs less than it does — no disposal to run, no scope filled after
|
|
92
|
+
it is created — didi is the one to take.
|
|
93
|
+
|
|
94
|
+
|
|
16
95
|
---
|
|
17
96
|
|
|
18
97
|
Part of [Fougere](https://github.com/chok/fougere) — one schema, a gradient from
|
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;AAqK1F,wBAAgB,eAAe,IAAI,SAAS,CAE3C"}
|
package/dist/create.js
CHANGED
|
@@ -9,6 +9,11 @@ function createScope(parent) {
|
|
|
9
9
|
// never the other way round.
|
|
10
10
|
const children = [];
|
|
11
11
|
let fallback;
|
|
12
|
+
// The names being built right now, shared by the whole tree: a miss here is answered by the
|
|
13
|
+
// parent and the descent continues there, so only one stack can name the path whole —
|
|
14
|
+
// `child.resolve('A')` reaching a parent's `B` that asks for `A` back reports `A → B → A`.
|
|
15
|
+
const resolving = parent?._resolving() ?? [];
|
|
16
|
+
const through = (name) => resolving.length > 0 ? ` (resolving: ${[...resolving, name].join(' → ')})` : '';
|
|
12
17
|
const remember = (value) => {
|
|
13
18
|
if (isDisposable(value))
|
|
14
19
|
built.push(value);
|
|
@@ -41,18 +46,29 @@ function createScope(parent) {
|
|
|
41
46
|
registry.set(name, { factory: () => made, lifetime: 'singleton', instance: made });
|
|
42
47
|
return made;
|
|
43
48
|
}
|
|
44
|
-
throw new Error(`[container] '${name}' is not registered`);
|
|
49
|
+
throw new Error(`[container] '${name}' is not registered${through(name)}`);
|
|
45
50
|
}
|
|
46
51
|
if (entry.instance !== undefined)
|
|
47
52
|
return entry.instance;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
if (resolving.includes(name)) {
|
|
54
|
+
throw new Error(`[container] dependency cycle: ${[...resolving, name].join(' → ')}`);
|
|
55
|
+
}
|
|
56
|
+
// Popped in a finally, because a constructor that throws leaves the name on the stack
|
|
57
|
+
// otherwise and the next resolution of it reports a cycle that is not there.
|
|
58
|
+
resolving.push(name);
|
|
59
|
+
try {
|
|
60
|
+
const value = entry.factory(container);
|
|
61
|
+
// The container disposes what it KEEPS: a transient is handed over and forgotten,
|
|
62
|
+
// and its caller is the one who knows when it is done.
|
|
63
|
+
if (entry.lifetime === 'singleton') {
|
|
64
|
+
entry.instance = value;
|
|
65
|
+
remember(value);
|
|
66
|
+
}
|
|
67
|
+
return value;
|
|
68
|
+
}
|
|
69
|
+
finally {
|
|
70
|
+
resolving.pop();
|
|
54
71
|
}
|
|
55
|
-
return value;
|
|
56
72
|
},
|
|
57
73
|
has(name) {
|
|
58
74
|
return registry.has(name) || (parent?.has(name) ?? false);
|
|
@@ -99,6 +115,9 @@ function createScope(parent) {
|
|
|
99
115
|
_getEntry(name) {
|
|
100
116
|
return registry.get(name) ?? parent?._getEntry(name);
|
|
101
117
|
},
|
|
118
|
+
_resolving() {
|
|
119
|
+
return resolving;
|
|
120
|
+
},
|
|
102
121
|
_forget(child) {
|
|
103
122
|
const at = children.indexOf(child);
|
|
104
123
|
if (at !== -1)
|
package/dist/create.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.js","sourceRoot":"","sources":["../src/create.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"create.js","sourceRoot":"","sources":["../src/create.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/create.ts
CHANGED
|
@@ -10,6 +10,7 @@ interface ScopeContainer extends Container {
|
|
|
10
10
|
_getEntry(name: string): Entry | undefined;
|
|
11
11
|
_getFallback(): ((name: string) => unknown) | undefined;
|
|
12
12
|
_forget(child: ScopeContainer): void;
|
|
13
|
+
_resolving(): string[];
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
const isDisposable = (value: unknown): value is Disposable =>
|
|
@@ -25,6 +26,13 @@ function createScope(parent?: ScopeContainer): ScopeContainer {
|
|
|
25
26
|
// never the other way round.
|
|
26
27
|
const children: ScopeContainer[] = [];
|
|
27
28
|
let fallback: ((name: string) => unknown) | undefined;
|
|
29
|
+
// The names being built right now, shared by the whole tree: a miss here is answered by the
|
|
30
|
+
// parent and the descent continues there, so only one stack can name the path whole —
|
|
31
|
+
// `child.resolve('A')` reaching a parent's `B` that asks for `A` back reports `A → B → A`.
|
|
32
|
+
const resolving: string[] = parent?._resolving() ?? [];
|
|
33
|
+
|
|
34
|
+
const through = (name: string) =>
|
|
35
|
+
resolving.length > 0 ? ` (resolving: ${[...resolving, name].join(' → ')})` : '';
|
|
28
36
|
|
|
29
37
|
const remember = <T>(value: T): T => {
|
|
30
38
|
if (isDisposable(value)) built.push(value);
|
|
@@ -62,18 +70,31 @@ function createScope(parent?: ScopeContainer): ScopeContainer {
|
|
|
62
70
|
registry.set(name, { factory: () => made, lifetime: 'singleton', instance: made });
|
|
63
71
|
return made as T;
|
|
64
72
|
}
|
|
65
|
-
throw new Error(`[container] '${name}' is not registered`);
|
|
73
|
+
throw new Error(`[container] '${name}' is not registered${through(name)}`);
|
|
66
74
|
}
|
|
67
75
|
|
|
68
76
|
if (entry.instance !== undefined) return entry.instance as T;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
|
|
78
|
+
if (resolving.includes(name)) {
|
|
79
|
+
throw new Error(`[container] dependency cycle: ${[...resolving, name].join(' → ')}`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Popped in a finally, because a constructor that throws leaves the name on the stack
|
|
83
|
+
// otherwise and the next resolution of it reports a cycle that is not there.
|
|
84
|
+
resolving.push(name);
|
|
85
|
+
try {
|
|
86
|
+
const value = entry.factory(container) as T;
|
|
87
|
+
// The container disposes what it KEEPS: a transient is handed over and forgotten,
|
|
88
|
+
// and its caller is the one who knows when it is done.
|
|
89
|
+
if (entry.lifetime === 'singleton') {
|
|
90
|
+
entry.instance = value;
|
|
91
|
+
remember(value);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return value;
|
|
95
|
+
} finally {
|
|
96
|
+
resolving.pop();
|
|
75
97
|
}
|
|
76
|
-
return value;
|
|
77
98
|
},
|
|
78
99
|
|
|
79
100
|
has(name: string): boolean {
|
|
@@ -124,6 +145,10 @@ function createScope(parent?: ScopeContainer): ScopeContainer {
|
|
|
124
145
|
return registry.get(name) ?? parent?._getEntry(name);
|
|
125
146
|
},
|
|
126
147
|
|
|
148
|
+
_resolving() {
|
|
149
|
+
return resolving;
|
|
150
|
+
},
|
|
151
|
+
|
|
127
152
|
_forget(child: ScopeContainer) {
|
|
128
153
|
const at = children.indexOf(child);
|
|
129
154
|
if (at !== -1) children.splice(at, 1);
|