@aponiajs/core 0.3.16 → 0.3.18

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.
Files changed (2) hide show
  1. package/dist/index.mjs +63 -25
  2. package/package.json +2 -2
package/dist/index.mjs CHANGED
@@ -4,10 +4,15 @@ var ModuleGraph = class {
4
4
  root;
5
5
  modules;
6
6
  #moduleSet;
7
+ #providersByModule;
8
+ #exportsByModule;
9
+ #locationsByModule = /* @__PURE__ */ new Map();
7
10
  constructor(root, modules) {
8
11
  this.root = root;
9
12
  this.modules = Object.freeze([...modules]);
10
13
  this.#moduleSet = new Set(modules);
14
+ this.#providersByModule = new Map(modules.map((module) => [module, new Map(module.providers.map((provider) => [provider.provide, provider]))]));
15
+ this.#exportsByModule = new Map(modules.map((module) => [module, new Set(module.exports)]));
11
16
  }
12
17
  inspect() {
13
18
  return Object.freeze({
@@ -26,31 +31,54 @@ var ModuleGraph = class {
26
31
  module: module.id,
27
32
  token: tokenName(token)
28
33
  });
29
- return this.#locate(module, token, /* @__PURE__ */ new Set());
34
+ const cached = this.#locationsByModule.get(module)?.get(token);
35
+ if (cached) return cached;
36
+ const location = this.#locate(module, token, /* @__PURE__ */ new Set());
37
+ this.#cacheLocation(module, token, location);
38
+ return location;
30
39
  }
31
40
  #locate(module, token, visited) {
32
- const own = module.providers.find((provider) => provider.provide === token);
33
- if (own) return {
34
- module,
35
- provider: own
36
- };
41
+ const cached = this.#locationsByModule.get(module)?.get(token);
42
+ if (cached) return cached;
43
+ const own = this.#providersByModule.get(module)?.get(token);
44
+ if (own) {
45
+ const location = Object.freeze({
46
+ module,
47
+ provider: own
48
+ });
49
+ this.#cacheLocation(module, token, location);
50
+ return location;
51
+ }
37
52
  if (visited.has(module)) throw missingProvider(module, token);
38
53
  visited.add(module);
39
- const candidates = /* @__PURE__ */ new Map();
40
- for (const imported of module.imports) {
41
- if (!imported.exports.includes(token)) continue;
42
- const location = this.#locate(imported, token, new Set(visited));
43
- candidates.set(location.provider, location);
54
+ try {
55
+ const candidates = /* @__PURE__ */ new Map();
56
+ for (const imported of module.imports) {
57
+ if (!this.#exportsByModule.get(imported)?.has(token)) continue;
58
+ const location = this.#locate(imported, token, visited);
59
+ candidates.set(location.module, location);
60
+ }
61
+ if (candidates.size === 0) throw missingProvider(module, token);
62
+ if (candidates.size > 1) throw new AponiaError("AMBIGUOUS_PROVIDER", `Token "${tokenName(token)}" is exported by multiple imports of module "${module.id}".`, {
63
+ module: module.id,
64
+ token: tokenName(token),
65
+ candidates: [...candidates.values()].map((item) => item.module.id)
66
+ });
67
+ const location = candidates.values().next().value;
68
+ if (!location) throw missingProvider(module, token);
69
+ this.#cacheLocation(module, token, location);
70
+ return location;
71
+ } finally {
72
+ visited.delete(module);
44
73
  }
45
- if (candidates.size === 0) throw missingProvider(module, token);
46
- if (candidates.size > 1) throw new AponiaError("AMBIGUOUS_PROVIDER", `Token "${tokenName(token)}" is exported by multiple imports of module "${module.id}".`, {
47
- module: module.id,
48
- token: tokenName(token),
49
- candidates: [...candidates.values()].map((item) => item.module.id)
50
- });
51
- const location = candidates.values().next().value;
52
- if (!location) throw missingProvider(module, token);
53
- return location;
74
+ }
75
+ #cacheLocation(module, token, location) {
76
+ let moduleLocations = this.#locationsByModule.get(module);
77
+ if (!moduleLocations) {
78
+ moduleLocations = /* @__PURE__ */ new Map();
79
+ this.#locationsByModule.set(module, moduleLocations);
80
+ }
81
+ moduleLocations.set(token, location);
54
82
  }
55
83
  };
56
84
  function compileModuleGraph(root) {
@@ -154,15 +182,17 @@ var AponiaContainer = class {
154
182
  });
155
183
  }
156
184
  instantiateController(module, controller) {
157
- if (this.#controllers.has(controller)) return this.#controllers.get(controller);
185
+ const moduleControllers = this.#controllers.get(module);
186
+ if (moduleControllers?.has(controller)) return moduleControllers.get(controller);
158
187
  const dependencies = controller.inject.map((dependency) => this.#resolve(this.graph.locate(module, dependency)));
159
188
  const instance = Reflect.construct(controller.useClass, dependencies);
160
- this.#controllers.set(controller, instance);
189
+ this.#moduleCache(this.#controllers, module).set(controller, instance);
161
190
  return instance;
162
191
  }
163
192
  #resolve(location) {
164
- if (this.#instances.has(location.provider)) return this.#instances.get(location.provider);
165
- const cycleIndex = this.#resolving.findIndex((item) => item.provider === location.provider);
193
+ const moduleInstances = this.#instances.get(location.module);
194
+ if (moduleInstances?.has(location.provider)) return moduleInstances.get(location.provider);
195
+ const cycleIndex = this.#resolving.findIndex((item) => item.module === location.module && item.provider === location.provider);
166
196
  if (cycleIndex >= 0) {
167
197
  const cycle = [...this.#resolving.slice(cycleIndex), location].map((item) => `${item.module.id}:${tokenName(item.provider.provide)}`);
168
198
  throw new AponiaError("PROVIDER_CYCLE", `Provider dependency cycle detected: ${cycle.join(" -> ")}.`, { cycle });
@@ -171,12 +201,20 @@ var AponiaContainer = class {
171
201
  try {
172
202
  const dependencies = providerDependencies(location.provider).map((dependency) => this.#resolve(this.graph.locate(location.module, dependency)));
173
203
  const instance = instantiate(location.provider, dependencies);
174
- this.#instances.set(location.provider, instance);
204
+ this.#moduleCache(this.#instances, location.module).set(location.provider, instance);
175
205
  return instance;
176
206
  } finally {
177
207
  this.#resolving.pop();
178
208
  }
179
209
  }
210
+ #moduleCache(cache, module) {
211
+ let moduleCache = cache.get(module);
212
+ if (!moduleCache) {
213
+ moduleCache = /* @__PURE__ */ new Map();
214
+ cache.set(module, moduleCache);
215
+ }
216
+ return moduleCache;
217
+ }
180
218
  };
181
219
  function createContainer(root) {
182
220
  return new AponiaContainer(compileModuleGraph(root));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aponiajs/core",
3
- "version": "0.3.16",
3
+ "version": "0.3.18",
4
4
  "description": "Module graph and dependency injection runtime for Aponia.",
5
5
  "homepage": "https://github.com/aponiajs/aponiajs#readme",
6
6
  "bugs": {
@@ -33,6 +33,6 @@
33
33
  "prepublishOnly": "bun run build"
34
34
  },
35
35
  "dependencies": {
36
- "@aponiajs/common": "0.3.11"
36
+ "@aponiajs/common": "0.3.18"
37
37
  }
38
38
  }