@djodjonx/neo-syringe 1.2.0 → 1.2.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.
Files changed (42) hide show
  1. package/.github/workflows/docs.yml +59 -0
  2. package/CHANGELOG.md +14 -0
  3. package/README.md +72 -779
  4. package/dist/cli/index.cjs +15 -0
  5. package/dist/cli/index.mjs +15 -0
  6. package/dist/index.d.cts +1 -1
  7. package/dist/index.d.mts +1 -1
  8. package/dist/unplugin/index.cjs +31 -7
  9. package/dist/unplugin/index.d.cts +7 -5
  10. package/dist/unplugin/index.d.mts +7 -5
  11. package/dist/unplugin/index.mjs +31 -7
  12. package/docs/.vitepress/config.ts +109 -0
  13. package/docs/.vitepress/theme/custom.css +150 -0
  14. package/docs/.vitepress/theme/index.ts +17 -0
  15. package/docs/api/configuration.md +274 -0
  16. package/docs/api/functions.md +291 -0
  17. package/docs/api/types.md +158 -0
  18. package/docs/guide/basic-usage.md +267 -0
  19. package/docs/guide/cli.md +174 -0
  20. package/docs/guide/generated-code.md +284 -0
  21. package/docs/guide/getting-started.md +171 -0
  22. package/docs/guide/ide-plugin.md +203 -0
  23. package/docs/guide/injection-types.md +287 -0
  24. package/docs/guide/legacy-migration.md +333 -0
  25. package/docs/guide/lifecycle.md +223 -0
  26. package/docs/guide/parent-container.md +321 -0
  27. package/docs/guide/scoped-injections.md +271 -0
  28. package/docs/guide/what-is-neo-syringe.md +162 -0
  29. package/docs/guide/why-neo-syringe.md +219 -0
  30. package/docs/index.md +138 -0
  31. package/docs/public/logo.png +0 -0
  32. package/package.json +5 -3
  33. package/src/analyzer/types.ts +52 -52
  34. package/src/cli/index.ts +15 -0
  35. package/src/generator/Generator.ts +23 -1
  36. package/src/types.ts +1 -1
  37. package/src/unplugin/index.ts +13 -41
  38. package/tests/analyzer/AnalyzerDeclarative.test.ts +1 -1
  39. package/tests/e2e/container-integration.test.ts +19 -19
  40. package/tests/e2e/generated-code.test.ts +2 -2
  41. package/tsconfig.json +2 -1
  42. package/typedoc.json +0 -5
@@ -0,0 +1,162 @@
1
+ # What is Neo-Syringe?
2
+
3
+ Neo-Syringe is a **next-generation dependency injection system** for TypeScript that shifts resolution from **runtime** to **build-time**.
4
+
5
+ ## The Problem with Traditional DI
6
+
7
+ Traditional DI containers (InversifyJS, tsyringe, Awilix) all work the same way:
8
+
9
+ ```typescript
10
+ // Traditional approach
11
+ @injectable()
12
+ class UserService {
13
+ constructor(@inject(TYPES.ILogger) private logger: ILogger) {}
14
+ }
15
+
16
+ // At runtime
17
+ container.resolve(UserService); // ← Resolution happens HERE
18
+ ```
19
+
20
+ This approach has several drawbacks:
21
+
22
+ | Issue | Impact |
23
+ |-------|--------|
24
+ | **Runtime overhead** | DI container code shipped to production |
25
+ | **Reflection required** | Need `reflect-metadata` and decorators |
26
+ | **Interface erasure** | Must use Symbols or string tokens manually |
27
+ | **Late errors** | Missing bindings only discovered at runtime |
28
+ | **Framework coupling** | Classes polluted with DI decorators |
29
+
30
+ ## The Neo-Syringe Solution
31
+
32
+ Neo-Syringe works as a **compiler plugin** that analyzes your configuration and generates optimized code:
33
+
34
+ ```typescript
35
+ // Your code (pure TypeScript!)
36
+ interface ILogger {
37
+ log(msg: string): void;
38
+ }
39
+
40
+ class UserService {
41
+ constructor(private logger: ILogger) {}
42
+ }
43
+
44
+ // Configuration
45
+ export const container = defineBuilderConfig({
46
+ injections: [
47
+ { token: useInterface<ILogger>(), provider: ConsoleLogger },
48
+ { token: UserService }
49
+ ]
50
+ });
51
+ ```
52
+
53
+ At build time, this becomes:
54
+
55
+ ```typescript
56
+ // Generated code (no DI library!)
57
+ function create_UserService(container) {
58
+ return new UserService(container.resolve("ILogger"));
59
+ }
60
+
61
+ class NeoContainer {
62
+ resolve(token) {
63
+ if (token === "ILogger") return new ConsoleLogger();
64
+ if (token === UserService) return create_UserService(this);
65
+ }
66
+ }
67
+
68
+ export const container = new NeoContainer();
69
+ ```
70
+
71
+ ## Key Advantages
72
+
73
+ ### 🚀 Zero Runtime Overhead
74
+
75
+ No DI library shipped to production. Just pure factory functions that create instances directly.
76
+
77
+ ### ✨ Native Interface Support
78
+
79
+ Use `useInterface<ILogger>()` instead of managing Symbols. The compiler generates unique IDs automatically.
80
+
81
+ ### 🛡️ Compile-Time Safety
82
+
83
+ Errors are detected in your IDE before you even save the file:
84
+
85
+ - Circular dependencies
86
+ - Missing bindings
87
+ - Duplicate registrations
88
+ - Type mismatches
89
+
90
+ ### 📦 Pure Classes
91
+
92
+ Your business classes have **zero DI dependencies**:
93
+
94
+ ```typescript
95
+ // ✅ Pure TypeScript class
96
+ class UserService {
97
+ constructor(private logger: ILogger) {}
98
+ }
99
+
100
+ // ❌ Traditional approach (polluted)
101
+ @injectable()
102
+ class UserService {
103
+ constructor(@inject(TYPES.ILogger) private logger: ILogger) {}
104
+ }
105
+ ```
106
+
107
+ ### 🔄 Gradual Migration
108
+
109
+ Bridge existing containers while migrating:
110
+
111
+ ```typescript
112
+ export const container = defineBuilderConfig({
113
+ useContainer: legacyTsyringeContainer, // ← Delegate to legacy
114
+ injections: [
115
+ { token: NewService } // New services in Neo-Syringe
116
+ ]
117
+ });
118
+ ```
119
+
120
+ ## How It Works
121
+
122
+ ```
123
+ ┌─────────────────────────────────────────────────────────────┐
124
+ │ BUILD TIME │
125
+ ├─────────────────────────────────────────────────────────────┤
126
+ │ │
127
+ │ 1. defineBuilderConfig({...}) │
128
+ │ │ │
129
+ │ ▼ │
130
+ │ 2. TypeScript Plugin analyzes configuration │
131
+ │ │ │
132
+ │ ▼ │
133
+ │ 3. Generates optimized NeoContainer class │
134
+ │ │ │
135
+ │ ▼ │
136
+ │ 4. Replaces defineBuilderConfig with generated code │
137
+ │ │
138
+ └─────────────────────────────────────────────────────────────┘
139
+
140
+
141
+ ┌─────────────────────────────────────────────────────────────┐
142
+ │ RUNTIME │
143
+ ├─────────────────────────────────────────────────────────────┤
144
+ │ │
145
+ │ container.resolve(UserService) │
146
+ │ │ │
147
+ │ ▼ │
148
+ │ Direct new UserService(new ConsoleLogger()) │
149
+ │ │
150
+ │ ✅ No reflection │
151
+ │ ✅ No container lookup │
152
+ │ ✅ Just function calls │
153
+ │ │
154
+ └─────────────────────────────────────────────────────────────┘
155
+ ```
156
+
157
+ ## Next Steps
158
+
159
+ - [Getting Started](/guide/getting-started) - Install and configure Neo-Syringe
160
+ - [Basic Usage](/guide/basic-usage) - Learn the core concepts
161
+ - [Why Neo-Syringe?](/guide/why-neo-syringe) - Detailed comparison with alternatives
162
+
@@ -0,0 +1,219 @@
1
+ # Why Neo-Syringe?
2
+
3
+ A detailed comparison with other dependency injection solutions.
4
+
5
+ ## Comparison Table
6
+
7
+ | Feature | Neo-Syringe | tsyringe | InversifyJS | Awilix |
8
+ |---------|:-----------:|:--------:|:-----------:|:------:|
9
+ | **Zero runtime overhead** | ✅ | ❌ | ❌ | ❌ |
10
+ | **No decorators needed** | ✅ | ❌ | ❌ | ✅ |
11
+ | **No reflect-metadata** | ✅ | ❌ | ❌ | ✅ |
12
+ | **Interface as tokens** | ✅ | ❌ | ❌ | ❌ |
13
+ | **Compile-time validation** | ✅ | ❌ | ❌ | ❌ |
14
+ | **IDE error detection** | ✅ | ❌ | ❌ | ❌ |
15
+ | **Tree-shakeable** | ✅ | ❌ | ❌ | ❌ |
16
+ | **Works in Edge/Workers** | ✅ | ⚠️ | ⚠️ | ✅ |
17
+
18
+ ## The Cost of Runtime DI
19
+
20
+ Traditional DI containers add significant overhead:
21
+
22
+ ### Bundle Size
23
+
24
+ | Library | Min+Gzip |
25
+ |---------|----------|
26
+ | InversifyJS | ~11 KB |
27
+ | tsyringe | ~4 KB |
28
+ | Awilix | ~8 KB |
29
+ | **Neo-Syringe** | **~0 KB** (generated) |
30
+
31
+ ### Runtime Performance
32
+
33
+ ```typescript
34
+ // Traditional (tsyringe) - Runtime resolution
35
+ container.resolve(UserService);
36
+ // 1. Look up token in registry
37
+ // 2. Check if singleton exists
38
+ // 3. Resolve all dependencies recursively
39
+ // 4. Create instance with reflection
40
+ // 5. Store singleton reference
41
+
42
+ // Neo-Syringe - Direct instantiation
43
+ container.resolve(UserService);
44
+ // 1. Call generated factory function
45
+ // That's it!
46
+ ```
47
+
48
+ ## Code Quality Comparison
49
+
50
+ ### Traditional Approach (tsyringe)
51
+
52
+ ```typescript
53
+ import 'reflect-metadata';
54
+ import { injectable, inject } from 'tsyringe';
55
+
56
+ // Must define symbols manually
57
+ const TYPES = {
58
+ ILogger: Symbol.for('ILogger'),
59
+ IDatabase: Symbol.for('IDatabase'),
60
+ };
61
+
62
+ // Classes polluted with decorators
63
+ @injectable()
64
+ class UserService {
65
+ constructor(
66
+ @inject(TYPES.ILogger) private logger: ILogger,
67
+ @inject(TYPES.IDatabase) private db: IDatabase
68
+ ) {}
69
+ }
70
+
71
+ // Registration
72
+ container.register(TYPES.ILogger, { useClass: ConsoleLogger });
73
+ container.register(TYPES.IDatabase, { useClass: PostgresDatabase });
74
+ container.register(UserService, { useClass: UserService });
75
+ ```
76
+
77
+ ### Neo-Syringe Approach
78
+
79
+ ```typescript
80
+ import { defineBuilderConfig, useInterface } from '@djodjonx/neo-syringe';
81
+
82
+ // Pure class - no DI imports!
83
+ class UserService {
84
+ constructor(
85
+ private logger: ILogger,
86
+ private db: IDatabase
87
+ ) {}
88
+ }
89
+
90
+ // Clean configuration
91
+ export const container = defineBuilderConfig({
92
+ injections: [
93
+ { token: useInterface<ILogger>(), provider: ConsoleLogger },
94
+ { token: useInterface<IDatabase>(), provider: PostgresDatabase },
95
+ { token: UserService }
96
+ ]
97
+ });
98
+ ```
99
+
100
+ ## Error Detection
101
+
102
+ ### Traditional: Runtime Errors
103
+
104
+ ```typescript
105
+ // tsyringe - Error at RUNTIME
106
+ container.resolve(UserService);
107
+ // Error: Attempted to resolve unregistered dependency token: "ILogger"
108
+ // 💥 App crashes in production!
109
+ ```
110
+
111
+ ### Neo-Syringe: Compile-Time Errors
112
+
113
+ ```typescript
114
+ // Neo-Syringe - Error in IDE instantly
115
+ export const container = defineBuilderConfig({
116
+ injections: [
117
+ { token: UserService } // UserService needs ILogger
118
+ ]
119
+ });
120
+ // 🔴 [Neo-Syringe] Missing binding: 'UserService' depends on 'ILogger'
121
+ // ✅ Fixed before you even save the file!
122
+ ```
123
+
124
+ ## Testing
125
+
126
+ ### Traditional: Complex Mocking (tsyringe example)
127
+
128
+ ```typescript
129
+ // ❌ tsyringe requires manual container reset and re-registration
130
+ import { container } from 'tsyringe';
131
+
132
+ beforeEach(() => {
133
+ container.reset(); // tsyringe API, NOT Neo-Syringe!
134
+ container.register(TYPES.ILogger, { useClass: MockLogger });
135
+ container.register(TYPES.IDatabase, { useClass: MockDatabase });
136
+ container.register(UserService, { useClass: UserService });
137
+ });
138
+ ```
139
+
140
+ ### Neo-Syringe: Natural Overrides
141
+
142
+ ```typescript
143
+ // ✅ Neo-Syringe - Create a test container that overrides production services
144
+ import { defineBuilderConfig, useInterface } from '@djodjonx/neo-syringe';
145
+ import { productionContainer } from './container';
146
+
147
+ // Test container inherits from production but overrides specific services
148
+ const testContainer = defineBuilderConfig({
149
+ useContainer: productionContainer,
150
+ injections: [
151
+ { token: useInterface<ILogger>(), provider: MockLogger, scoped: true },
152
+ { token: useInterface<IDatabase>(), provider: MockDatabase, scoped: true }
153
+ ]
154
+ });
155
+
156
+ // No reset needed - each test file can have its own container!
157
+ const userService = testContainer.resolve(UserService);
158
+ ```
159
+
160
+ ## Edge Computing / Workers
161
+
162
+ Traditional DI often fails in edge environments:
163
+
164
+ ```typescript
165
+ // ❌ tsyringe in Cloudflare Workers
166
+ // Error: reflect-metadata requires global Reflect object
167
+
168
+ // ❌ InversifyJS in Vercel Edge
169
+ // Error: Cannot use decorators in Edge Runtime
170
+ ```
171
+
172
+ Neo-Syringe works everywhere:
173
+
174
+ ```typescript
175
+ // ✅ Neo-Syringe in any environment
176
+ // Generated code is pure JavaScript
177
+ export class NeoContainer {
178
+ resolve(token) {
179
+ if (token === "ILogger") return new ConsoleLogger();
180
+ // ... pure function calls
181
+ }
182
+ }
183
+ ```
184
+
185
+ ## Migration Path
186
+
187
+ You don't have to migrate everything at once:
188
+
189
+ ```typescript
190
+ // Bridge legacy container
191
+ import { legacyContainer } from './legacy-tsyringe';
192
+ import { declareContainerTokens } from '@djodjonx/neo-syringe';
193
+
194
+ const legacy = declareContainerTokens<{
195
+ AuthService: AuthService;
196
+ UserRepository: UserRepository;
197
+ }>(legacyContainer);
198
+
199
+ // New services use Neo-Syringe
200
+ export const container = defineBuilderConfig({
201
+ useContainer: legacy, // Delegate to legacy
202
+ injections: [
203
+ { token: NewService },
204
+ { token: AnotherNewService }
205
+ ]
206
+ });
207
+ ```
208
+
209
+ ## Summary
210
+
211
+ | Aspect | Traditional DI | Neo-Syringe |
212
+ |--------|---------------|-------------|
213
+ | **When errors occur** | Runtime | Compile-time |
214
+ | **Bundle impact** | 4-11 KB | 0 KB |
215
+ | **Class purity** | Polluted with decorators | 100% pure |
216
+ | **Interface support** | Manual Symbols | Automatic |
217
+ | **Edge compatibility** | Limited | Full |
218
+ | **Performance** | Map lookups + reflection | Direct calls |
219
+
package/docs/index.md ADDED
@@ -0,0 +1,138 @@
1
+ ---
2
+ layout: home
3
+
4
+ hero:
5
+ name: Neo-Syringe
6
+ text: Compile-Time DI
7
+ tagline: Zero-overhead dependency injection that shifts resolution from Runtime to Build-Time. No reflection, no decorators, just pure TypeScript.
8
+ image:
9
+ src: /logo.png
10
+ alt: Neo-Syringe
11
+ actions:
12
+ - theme: brand
13
+ text: Get Started
14
+ link: /guide/getting-started
15
+ - theme: alt
16
+ text: View on GitHub
17
+ link: https://github.com/djodjonx/neo-syringe
18
+
19
+ features:
20
+ - icon: ✨
21
+ title: Interface as Tokens
22
+ details: Native support for useInterface<ILogger>() without manual Symbols. TypeScript interfaces work seamlessly.
23
+
24
+ - icon: 🚀
25
+ title: Zero Runtime Overhead
26
+ details: No reflection, no reflect-metadata. Just pure factory functions generated at build time.
27
+
28
+ - icon: 🛡️
29
+ title: Compile-Time Safety
30
+ details: Detect circular dependencies, missing bindings, and type mismatches instantly in your IDE.
31
+
32
+ - icon: 🔄
33
+ title: Gradual Migration
34
+ details: Bridge existing containers like tsyringe or InversifyJS with useContainer while migrating.
35
+
36
+ - icon: 📦
37
+ title: Pure Classes
38
+ details: Your business classes stay 100% pure - no decorators, no DI imports, no framework coupling.
39
+
40
+ - icon: 🤖
41
+ title: CI Validation
42
+ details: Standalone CLI to verify your dependency graph before deployment.
43
+ ---
44
+
45
+ <style>
46
+ :root {
47
+ --vp-home-hero-name-color: transparent;
48
+ --vp-home-hero-name-background: linear-gradient(135deg, #0d9488 0%, #f97316 100%);
49
+ }
50
+ </style>
51
+
52
+ ## Why Choose Neo-Syringe?
53
+
54
+ Traditional DI containers like InversifyJS and tsyringe rely on **runtime resolution**:
55
+
56
+ - ❌ Ship DI container logic to the browser
57
+ - ❌ Errors happen at runtime
58
+ - ❌ Interfaces are erased, requiring manual Symbols
59
+ - ❌ Need decorators and reflect-metadata
60
+
61
+ **Neo-Syringe is different.** It works as a **compiler plugin**:
62
+
63
+ - ✅ Generate optimized factories at build time
64
+ - ✅ Errors detected in your IDE
65
+ - ✅ Automatic interface IDs
66
+ - ✅ Pure TypeScript, no decorators
67
+
68
+ ## Quick Example
69
+
70
+ ```typescript
71
+ // Pure TypeScript - no decorators!
72
+ interface ILogger {
73
+ log(msg: string): void;
74
+ }
75
+
76
+ class ConsoleLogger implements ILogger {
77
+ log(msg: string) { console.log(msg); }
78
+ }
79
+
80
+ class UserService {
81
+ constructor(private logger: ILogger) {}
82
+ }
83
+
84
+ // Configure the container
85
+ import { defineBuilderConfig, useInterface } from '@djodjonx/neo-syringe';
86
+
87
+ export const container = defineBuilderConfig({
88
+ name: 'AppContainer',
89
+ injections: [
90
+ { token: useInterface<ILogger>(), provider: ConsoleLogger },
91
+ { token: UserService }
92
+ ]
93
+ });
94
+
95
+ // Use it
96
+ const userService = container.resolve(UserService);
97
+ ```
98
+
99
+ ## Generated Output
100
+
101
+ The build plugin transforms your configuration into optimized code:
102
+
103
+ ```typescript
104
+ // Generated at build time
105
+ function create_ILogger() {
106
+ return new ConsoleLogger();
107
+ }
108
+
109
+ function create_UserService(container) {
110
+ return new UserService(container.resolve("ILogger"));
111
+ }
112
+
113
+ export class NeoContainer {
114
+ resolve(token) {
115
+ if (token === "ILogger") return this.getInstance("ILogger", create_ILogger);
116
+ if (token === UserService) return this.getInstance(UserService, create_UserService);
117
+ throw new Error(`Service not found: ${token}`);
118
+ }
119
+ }
120
+ ```
121
+
122
+ **Zero DI library shipped to production!**
123
+
124
+ <div style="text-align: center; margin-top: 3rem;">
125
+ <a href="./guide/getting-started" style="
126
+ display: inline-block;
127
+ padding: 12px 24px;
128
+ background: linear-gradient(135deg, #0d9488 0%, #14b8a6 100%);
129
+ color: white;
130
+ text-decoration: none;
131
+ border-radius: 8px;
132
+ font-weight: 600;
133
+ transition: transform 0.2s;
134
+ ">
135
+ Get Started →
136
+ </a>
137
+ </div>
138
+
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@djodjonx/neo-syringe",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "Zero-Overhead, Compile-Time Dependency Injection for TypeScript",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -36,7 +36,9 @@
36
36
  "validate": "pnpm lint && pnpm typecheck && pnpm test",
37
37
  "prebuild": "pnpm validate",
38
38
  "prepublishOnly": "pnpm build",
39
- "docs": "typedoc",
39
+ "docs:dev": "vitepress dev docs",
40
+ "docs:build": "vitepress build docs",
41
+ "docs:preview": "vitepress preview docs",
40
42
  "release": "pnpm validate && standard-version",
41
43
  "release:dry": "standard-version --dry-run",
42
44
  "prepare": "husky"
@@ -66,9 +68,9 @@
66
68
  "standard-version": "^9.5.0",
67
69
  "tsdown": "0.20.0-beta.3",
68
70
  "tsyringe": "^4.10.0",
69
- "typedoc": "^0.28.16",
70
71
  "typescript": "^5.9.3",
71
72
  "unplugin": "^2.3.11",
73
+ "vitepress": "^1.6.4",
72
74
  "vitest": "^4.0.17"
73
75
  }
74
76
  }
@@ -1,93 +1,93 @@
1
1
  import type { Symbol, Node } from 'typescript';
2
2
 
3
- export type TokenId = string; // Unique identifier for the token (Interface Name or Class Name)
3
+ /**
4
+ * Unique identifier for a token (interface name or class name).
5
+ */
6
+ export type TokenId = string;
4
7
 
8
+ /**
9
+ * How a service was registered in the container.
10
+ * - `explicit`: Provider was explicitly specified.
11
+ * - `autowire`: Token is both the token and provider (self-binding).
12
+ * - `parent`: Inherited from parent container.
13
+ * - `factory`: Provider is a factory function.
14
+ */
5
15
  export type RegistrationType = 'explicit' | 'autowire' | 'parent' | 'factory';
6
16
 
17
+ /**
18
+ * Represents a single service definition in the dependency graph.
19
+ */
7
20
  export interface ServiceDefinition {
21
+ /** Unique identifier for this service token. */
8
22
  tokenId: TokenId;
23
+
9
24
  /**
10
- * The symbol of the concrete class implementation.
25
+ * The TypeScript symbol of the concrete class implementation.
11
26
  * Undefined if the provider is a factory function.
12
27
  */
13
28
  implementationSymbol?: Symbol;
14
29
 
15
30
  /**
16
- * The symbol of the token (if it is a Class/Value).
17
- * Undefined if the token is a Virtual Interface ID.
31
+ * The TypeScript symbol of the token (if it is a Class/Value).
32
+ * Undefined if the token is a virtual interface ID.
18
33
  */
19
34
  tokenSymbol?: Symbol;
20
35
 
21
- /**
22
- * The source node where the registration happened (for error reporting).
23
- */
36
+ /** The source node where the registration happened (for error reporting). */
24
37
  registrationNode: Node;
25
38
 
39
+ /** How this service was registered. */
26
40
  type: RegistrationType;
41
+
42
+ /** Lifecycle of the service instance. */
27
43
  lifecycle: 'singleton' | 'transient';
28
44
 
29
- /**
30
- * True if the token is an Interface (requires string literal key).
31
- * False if the token is a Class (requires reference key).
32
- */
45
+ /** True if the token is an interface (requires string literal key). */
33
46
  isInterfaceToken?: boolean;
34
47
 
35
- /**
36
- * True if the token is a Value Token (useToken<T>('name')).
37
- * Used for primitive values like string, number, boolean.
38
- */
48
+ /** True if the token is a value token for primitives. */
39
49
  isValueToken?: boolean;
40
50
 
41
- /**
42
- * True if the provider is a factory function.
43
- */
51
+ /** True if the provider is a factory function. */
44
52
  isFactory?: boolean;
45
53
 
46
- /**
47
- * The raw source text of the factory function (for code generation).
48
- */
54
+ /** The raw source text of the factory function (for code generation). */
49
55
  factorySource?: string;
50
56
 
51
- /**
52
- * True if this injection is scoped to the local container.
53
- * Allows overriding a token from a parent container without duplicate error.
54
- */
57
+ /** True if this injection is scoped to the local container. */
55
58
  isScoped?: boolean;
56
59
  }
57
60
 
61
+ /**
62
+ * A node in the dependency graph representing a service and its dependencies.
63
+ */
58
64
  export interface DependencyNode {
65
+ /** The service definition. */
59
66
  service: ServiceDefinition;
60
- /**
61
- * The dependencies required by this service's constructor.
62
- * Maps parameter index to the TokenId it depends on.
63
- */
67
+
68
+ /** Token IDs of dependencies required by this service's constructor. */
64
69
  dependencies: TokenId[];
65
70
  }
66
71
 
72
+ /**
73
+ * Complete dependency graph for a container configuration.
74
+ */
67
75
  export interface DependencyGraph {
76
+ /** All service nodes indexed by their token ID. */
68
77
  nodes: Map<TokenId, DependencyNode>;
69
- /**
70
- * The root services that are explicitly requested or exported.
71
- */
78
+
79
+ /** Root services that are explicitly requested or exported. */
72
80
  roots: TokenId[];
73
- /**
74
- * Arguments passed to the .build() method call.
75
- * Captured as raw source text to be injected into the generated constructor.
76
- */
81
+
82
+ /** Arguments passed to the .build() method call (raw source text). */
77
83
  buildArguments?: string[];
78
- /**
79
- * The optional name of the container for debugging.
80
- */
81
- containerName?: string;
82
-
83
- /**
84
- * List of legacy container variable names to delegate to.
85
- */
86
- legacyContainers?: string[];
87
-
88
- /**
89
- * Tokens provided by the parent container (useContainer).
90
- * Used for validation - these tokens don't need local bindings.
91
- */
92
- parentProvidedTokens?: Set<TokenId>;
93
- }
84
+
85
+ /** Optional container name for debugging. */
86
+ containerName?: string;
87
+
88
+ /** Legacy container variable names to delegate to. */
89
+ legacyContainers?: string[];
90
+
91
+ /** Tokens provided by the parent container (used for validation). */
92
+ parentProvidedTokens?: Set<TokenId>;
93
+ }