katagami 2.0.0 → 2.2.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.
@@ -13,29 +13,29 @@ function createScope(source) {
13
13
  if (internals.isDisposed()) {
14
14
  throw new ContainerError("Cannot create a scope from a disposed container.");
15
15
  }
16
- return new Scope(internals.registrations, internals.instances);
16
+ return new Scope(internals.registrations, internals.singletonCache);
17
17
  }
18
18
 
19
19
  class Scope {
20
20
  registrations;
21
- singletonInstances;
22
- scopedInstances;
21
+ singletonCache;
22
+ scopedCache;
23
23
  resolvingTokens;
24
24
  disposed = false;
25
25
  [INTERNALS];
26
- constructor(registrations, singletonInstances) {
26
+ constructor(registrations, singletonCache) {
27
27
  this.registrations = registrations;
28
- this.singletonInstances = singletonInstances;
29
- this.scopedInstances = new Map;
28
+ this.singletonCache = singletonCache;
29
+ this.scopedCache = new Map;
30
30
  this.resolvingTokens = new Set;
31
31
  this[INTERNALS] = {
32
- instances: this.singletonInstances,
33
32
  isDisposed: () => this.disposed,
34
33
  markDisposed: () => {
35
34
  this.disposed = true;
36
35
  },
37
- ownInstances: this.scopedInstances,
38
- registrations: this.registrations
36
+ ownCache: this.scopedCache,
37
+ registrations: this.registrations,
38
+ singletonCache: this.singletonCache
39
39
  };
40
40
  }
41
41
  resolve(token) {
@@ -44,25 +44,32 @@ class Scope {
44
44
  tryResolve(token) {
45
45
  return this.resolveToken(token, false);
46
46
  }
47
+ resolveAll(token) {
48
+ return this.resolveAllTokens(token, true);
49
+ }
50
+ tryResolveAll(token) {
51
+ return this.resolveAllTokens(token, false);
52
+ }
47
53
  resolveToken(token, required) {
48
54
  if (this.disposed) {
49
55
  throw new ContainerError("Cannot resolve from a disposed scope.");
50
56
  }
51
- const singletonCached = this.singletonInstances.get(token);
57
+ const registrations = this.registrations.get(token);
58
+ if (registrations === undefined || registrations.length === 0) {
59
+ if (required) {
60
+ throw new ContainerError(`Token "${tokenToString(token)}" is not registered.`);
61
+ }
62
+ return;
63
+ }
64
+ const registration = registrations[registrations.length - 1];
65
+ const singletonCached = this.singletonCache.get(registration);
52
66
  if (singletonCached !== undefined) {
53
67
  return singletonCached;
54
68
  }
55
- const scopedCached = this.scopedInstances.get(token);
69
+ const scopedCached = this.scopedCache.get(registration);
56
70
  if (scopedCached !== undefined) {
57
71
  return scopedCached;
58
72
  }
59
- const registration = this.registrations.get(token);
60
- if (registration === undefined) {
61
- if (required) {
62
- throw new ContainerError(`Token "${tokenToString(token)}" is not registered.`);
63
- }
64
- return;
65
- }
66
73
  if (this.resolvingTokens.has(token)) {
67
74
  throw new ContainerError(`Circular dependency detected: ${buildCircularPath(this.resolvingTokens, token)}`);
68
75
  }
@@ -70,15 +77,53 @@ class Scope {
70
77
  try {
71
78
  const instance = registration.factory(this);
72
79
  if (registration.lifetime === "singleton") {
73
- this.singletonInstances.set(token, instance);
80
+ this.singletonCache.set(registration, instance);
74
81
  } else if (registration.lifetime === "scoped") {
75
- this.scopedInstances.set(token, instance);
82
+ this.scopedCache.set(registration, instance);
76
83
  }
77
84
  return instance;
78
85
  } finally {
79
86
  this.resolvingTokens.delete(token);
80
87
  }
81
88
  }
89
+ resolveAllTokens(token, required) {
90
+ if (this.disposed) {
91
+ throw new ContainerError("Cannot resolve from a disposed scope.");
92
+ }
93
+ const registrations = this.registrations.get(token);
94
+ if (registrations === undefined || registrations.length === 0) {
95
+ if (required) {
96
+ throw new ContainerError(`Token "${tokenToString(token)}" is not registered.`);
97
+ }
98
+ return;
99
+ }
100
+ if (this.resolvingTokens.has(token)) {
101
+ throw new ContainerError(`Circular dependency detected: ${buildCircularPath(this.resolvingTokens, token)}`);
102
+ }
103
+ this.resolvingTokens.add(token);
104
+ try {
105
+ return registrations.map((registration) => {
106
+ const reg = registration;
107
+ const singletonCached = this.singletonCache.get(registration);
108
+ if (singletonCached !== undefined) {
109
+ return singletonCached;
110
+ }
111
+ const scopedCached = this.scopedCache.get(registration);
112
+ if (scopedCached !== undefined) {
113
+ return scopedCached;
114
+ }
115
+ const instance = reg.factory(this);
116
+ if (reg.lifetime === "singleton") {
117
+ this.singletonCache.set(registration, instance);
118
+ } else if (reg.lifetime === "scoped") {
119
+ this.scopedCache.set(registration, instance);
120
+ }
121
+ return instance;
122
+ });
123
+ } finally {
124
+ this.resolvingTokens.delete(token);
125
+ }
126
+ }
82
127
  }
83
128
  export {
84
129
  createScope,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "katagami",
3
- "version": "2.0.0",
3
+ "version": "2.2.0",
4
4
  "description": "Lightweight DI container for TypeScript and JavaScript — full type inference, no decorators, no reflect-metadata, hybrid class & PropertyKey tokens.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -20,6 +20,11 @@
20
20
  "types": "./dist/disposable/index.d.ts",
21
21
  "import": "./dist/disposable/index.js",
22
22
  "require": "./dist/disposable/index.cjs"
23
+ },
24
+ "./lazy": {
25
+ "types": "./dist/lazy/index.d.ts",
26
+ "import": "./dist/lazy/index.js",
27
+ "require": "./dist/lazy/index.cjs"
23
28
  }
24
29
  },
25
30
  "main": "./dist/index.cjs",
@@ -45,14 +50,13 @@
45
50
  "clean": "rm -rf dist",
46
51
  "build": "bun run clean && bun run build:types && bun run build:esm && bun run build:cjs",
47
52
  "build:types": "tsc -p tsconfig.build.json",
48
- "build:esm": "bun build ./src/index.ts ./src/scope/index.ts ./src/disposable/index.ts --outdir dist --format esm --splitting",
49
- "build:cjs": "bun build ./src/index.ts --outfile dist/index.cjs --format cjs && bun build ./src/scope/index.ts --outfile dist/scope/index.cjs --format cjs && bun build ./src/disposable/index.ts --outfile dist/disposable/index.cjs --format cjs",
50
- "test": "bun test --coverage --dots",
53
+ "build:esm": "bun build ./src/index.ts ./src/scope/index.ts ./src/disposable/index.ts ./src/lazy/index.ts --outdir dist --format esm --splitting",
54
+ "build:cjs": "bun build ./src/index.ts --outfile dist/index.cjs --format cjs && bun build ./src/scope/index.ts --outfile dist/scope/index.cjs --format cjs && bun build ./src/disposable/index.ts --outfile dist/disposable/index.cjs --format cjs && bun build ./src/lazy/index.ts --outfile dist/lazy/index.cjs --format cjs",
51
55
  "prepublishOnly": "bun run build",
52
56
  "check": "bun run format",
53
57
  "lint": "biome lint .",
54
58
  "format": "biome check --write .",
55
- "verify": "bun run build:types && bun run check && bun run test"
59
+ "verify": "bun run build:types && bun run check && bun test"
56
60
  },
57
61
  "dependencies": {
58
62
  "@types/bun": "^1.3.8"