@djodjonx/neo-syringe 1.1.5 → 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 (61) hide show
  1. package/.github/workflows/ci.yml +6 -5
  2. package/.github/workflows/docs.yml +59 -0
  3. package/CHANGELOG.md +27 -0
  4. package/README.md +74 -740
  5. package/dist/{GraphValidator-G0F4QiLk.cjs → GraphValidator-CV4VoJl0.cjs} +18 -10
  6. package/dist/{GraphValidator-C8ldJtNp.mjs → GraphValidator-DXqqkNdS.mjs} +18 -10
  7. package/dist/cli/index.cjs +16 -1
  8. package/dist/cli/index.mjs +16 -1
  9. package/dist/index.d.cts +31 -5
  10. package/dist/index.d.mts +31 -5
  11. package/dist/lsp/index.cjs +1 -1
  12. package/dist/lsp/index.mjs +1 -1
  13. package/dist/unplugin/index.cjs +33 -9
  14. package/dist/unplugin/index.d.cts +7 -5
  15. package/dist/unplugin/index.d.mts +7 -5
  16. package/dist/unplugin/index.mjs +33 -9
  17. package/docs/.vitepress/config.ts +109 -0
  18. package/docs/.vitepress/theme/custom.css +150 -0
  19. package/docs/.vitepress/theme/index.ts +17 -0
  20. package/docs/api/configuration.md +274 -0
  21. package/docs/api/functions.md +291 -0
  22. package/docs/api/types.md +158 -0
  23. package/docs/guide/basic-usage.md +267 -0
  24. package/docs/guide/cli.md +174 -0
  25. package/docs/guide/generated-code.md +284 -0
  26. package/docs/guide/getting-started.md +171 -0
  27. package/docs/guide/ide-plugin.md +203 -0
  28. package/docs/guide/injection-types.md +287 -0
  29. package/docs/guide/legacy-migration.md +333 -0
  30. package/docs/guide/lifecycle.md +223 -0
  31. package/docs/guide/parent-container.md +321 -0
  32. package/docs/guide/scoped-injections.md +271 -0
  33. package/docs/guide/what-is-neo-syringe.md +162 -0
  34. package/docs/guide/why-neo-syringe.md +219 -0
  35. package/docs/index.md +138 -0
  36. package/docs/public/logo.png +0 -0
  37. package/package.json +15 -12
  38. package/src/analyzer/Analyzer.ts +20 -10
  39. package/src/analyzer/types.ts +55 -49
  40. package/src/cli/index.ts +15 -0
  41. package/src/generator/Generator.ts +24 -2
  42. package/src/generator/GraphValidator.ts +6 -2
  43. package/src/types.ts +30 -4
  44. package/src/unplugin/index.ts +13 -41
  45. package/tests/analyzer/Analyzer.test.ts +4 -4
  46. package/tests/analyzer/AnalyzerDeclarative.test.ts +1 -1
  47. package/tests/analyzer/Factory.test.ts +2 -2
  48. package/tests/analyzer/Scoped.test.ts +434 -0
  49. package/tests/cli/cli.test.ts +91 -0
  50. package/tests/e2e/container-integration.test.ts +21 -21
  51. package/tests/e2e/generated-code.test.ts +7 -7
  52. package/tests/e2e/scoped.test.ts +370 -0
  53. package/tests/e2e/snapshots.test.ts +2 -2
  54. package/tests/e2e/standalone.test.ts +2 -2
  55. package/tests/generator/ExternalGenerator.test.ts +1 -1
  56. package/tests/generator/FactoryGenerator.test.ts +6 -6
  57. package/tests/generator/Generator.test.ts +2 -2
  58. package/tests/generator/GeneratorDeclarative.test.ts +1 -1
  59. package/tests/generator/GraphValidator.test.ts +1 -1
  60. package/tsconfig.json +2 -1
  61. package/typedoc.json +0 -5
@@ -0,0 +1,109 @@
1
+ import { defineConfig } from 'vitepress'
2
+
3
+ export default defineConfig({
4
+ title: 'Neo-Syringe',
5
+ description: 'Zero-Overhead, Compile-Time Dependency Injection for TypeScript',
6
+
7
+ head: [
8
+ ['link', { rel: 'icon', href: '/logo.png' }],
9
+ ['meta', { name: 'theme-color', content: '#0d9488' }],
10
+ ['meta', { property: 'og:type', content: 'website' }],
11
+ ['meta', { property: 'og:title', content: 'Neo-Syringe' }],
12
+ ['meta', { property: 'og:description', content: 'Zero-Overhead, Compile-Time Dependency Injection for TypeScript' }],
13
+ ['meta', { property: 'og:image', content: '/logo.png' }],
14
+ ],
15
+
16
+ base: '/neo-syringe/',
17
+
18
+ themeConfig: {
19
+ logo: '/logo.png',
20
+
21
+ nav: [
22
+ { text: 'Guide', link: '/guide/getting-started' },
23
+ { text: 'API', link: '/api/types' },
24
+ {
25
+ text: 'Examples',
26
+ items: [
27
+ { text: 'Basic Usage', link: '/guide/basic-usage' },
28
+ { text: 'Parent Container', link: '/guide/parent-container' },
29
+ { text: 'Legacy Migration', link: '/guide/legacy-migration' },
30
+ ]
31
+ },
32
+ {
33
+ text: 'Links',
34
+ items: [
35
+ { text: 'GitHub', link: 'https://github.com/djodjonx/neo-syringe' },
36
+ { text: 'NPM', link: 'https://www.npmjs.com/package/@djodjonx/neo-syringe' },
37
+ { text: 'Changelog', link: 'https://github.com/djodjonx/neo-syringe/blob/main/CHANGELOG.md' },
38
+ ]
39
+ }
40
+ ],
41
+
42
+ sidebar: {
43
+ '/guide/': [
44
+ {
45
+ text: 'Introduction',
46
+ items: [
47
+ { text: 'What is Neo-Syringe?', link: '/guide/what-is-neo-syringe' },
48
+ { text: 'Getting Started', link: '/guide/getting-started' },
49
+ { text: 'Why Neo-Syringe?', link: '/guide/why-neo-syringe' },
50
+ ]
51
+ },
52
+ {
53
+ text: 'Core Concepts',
54
+ items: [
55
+ { text: 'Basic Usage', link: '/guide/basic-usage' },
56
+ { text: 'Injection Types', link: '/guide/injection-types' },
57
+ { text: 'Lifecycle', link: '/guide/lifecycle' },
58
+ { text: 'Scoped Injections', link: '/guide/scoped-injections' },
59
+ ]
60
+ },
61
+ {
62
+ text: 'Advanced',
63
+ items: [
64
+ { text: 'Parent Container', link: '/guide/parent-container' },
65
+ { text: 'Legacy Migration', link: '/guide/legacy-migration' },
66
+ { text: 'Generated Code', link: '/guide/generated-code' },
67
+ ]
68
+ },
69
+ {
70
+ text: 'Tools',
71
+ items: [
72
+ { text: 'CLI Validator', link: '/guide/cli' },
73
+ { text: 'IDE Plugin', link: '/guide/ide-plugin' },
74
+ ]
75
+ }
76
+ ],
77
+ '/api/': [
78
+ {
79
+ text: 'API Reference',
80
+ items: [
81
+ { text: 'Types', link: '/api/types' },
82
+ { text: 'Functions', link: '/api/functions' },
83
+ { text: 'Configuration', link: '/api/configuration' },
84
+ ]
85
+ }
86
+ ]
87
+ },
88
+
89
+ socialLinks: [
90
+ { icon: 'github', link: 'https://github.com/djodjonx/neo-syringe' },
91
+ { icon: 'npm', link: 'https://www.npmjs.com/package/@djodjonx/neo-syringe' }
92
+ ],
93
+
94
+ footer: {
95
+ message: 'Released under the MIT License.',
96
+ copyright: 'Copyright © 2024-present Neo-Syringe Contributors'
97
+ },
98
+
99
+ search: {
100
+ provider: 'local'
101
+ },
102
+
103
+ editLink: {
104
+ pattern: 'https://github.com/djodjonx/neo-syringe/edit/main/docs/:path',
105
+ text: 'Edit this page on GitHub'
106
+ }
107
+ }
108
+ })
109
+
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Neo-Syringe Custom Theme
3
+ * Colors: Teal (#0d9488) + Orange (#f97316)
4
+ */
5
+
6
+ :root {
7
+ /* Brand Colors */
8
+ --neo-teal: #0d9488;
9
+ --neo-teal-light: #14b8a6;
10
+ --neo-teal-dark: #0f766e;
11
+ --neo-orange: #f97316;
12
+ --neo-orange-light: #fb923c;
13
+ --neo-orange-dark: #ea580c;
14
+
15
+ /* VitePress Color Overrides */
16
+ --vp-c-brand-1: var(--neo-teal);
17
+ --vp-c-brand-2: var(--neo-teal-light);
18
+ --vp-c-brand-3: var(--neo-teal-dark);
19
+ --vp-c-brand-soft: rgba(13, 148, 136, 0.14);
20
+
21
+ /* Accent for highlights */
22
+ --vp-c-tip-1: var(--neo-teal);
23
+ --vp-c-tip-2: var(--neo-teal-light);
24
+ --vp-c-tip-3: var(--neo-teal-dark);
25
+ --vp-c-tip-soft: rgba(13, 148, 136, 0.14);
26
+
27
+ /* Warning with orange */
28
+ --vp-c-warning-1: var(--neo-orange);
29
+ --vp-c-warning-2: var(--neo-orange-light);
30
+ --vp-c-warning-3: var(--neo-orange-dark);
31
+ --vp-c-warning-soft: rgba(249, 115, 22, 0.14);
32
+
33
+ /* Button colors */
34
+ --vp-button-brand-border: transparent;
35
+ --vp-button-brand-text: #fff;
36
+ --vp-button-brand-bg: var(--neo-teal);
37
+ --vp-button-brand-hover-border: transparent;
38
+ --vp-button-brand-hover-text: #fff;
39
+ --vp-button-brand-hover-bg: var(--neo-teal-light);
40
+ --vp-button-brand-active-border: transparent;
41
+ --vp-button-brand-active-text: #fff;
42
+ --vp-button-brand-active-bg: var(--neo-teal-dark);
43
+
44
+ /* Alt button with orange accent */
45
+ --vp-button-alt-border: var(--neo-orange);
46
+ --vp-button-alt-text: var(--neo-orange);
47
+ --vp-button-alt-bg: transparent;
48
+ --vp-button-alt-hover-border: var(--neo-orange-light);
49
+ --vp-button-alt-hover-text: var(--neo-orange-light);
50
+ --vp-button-alt-hover-bg: rgba(249, 115, 22, 0.1);
51
+
52
+ /* Home hero gradient */
53
+ --vp-home-hero-name-color: transparent;
54
+ --vp-home-hero-name-background: linear-gradient(135deg, var(--neo-teal) 0%, var(--neo-orange) 100%);
55
+
56
+ --vp-home-hero-image-background-image: linear-gradient(135deg, rgba(13, 148, 136, 0.3) 0%, rgba(249, 115, 22, 0.3) 100%);
57
+ --vp-home-hero-image-filter: blur(44px);
58
+ }
59
+
60
+ .dark {
61
+ --vp-c-brand-1: var(--neo-teal-light);
62
+ --vp-c-brand-2: var(--neo-teal);
63
+ --vp-c-brand-3: var(--neo-teal-dark);
64
+
65
+ --vp-home-hero-image-background-image: linear-gradient(135deg, rgba(13, 148, 136, 0.4) 0%, rgba(249, 115, 22, 0.4) 100%);
66
+ }
67
+
68
+ /* Hero section enhancements */
69
+ .VPHero .VPImage {
70
+ max-width: 280px;
71
+ max-height: 280px;
72
+ }
73
+
74
+ .VPHero .tagline {
75
+ font-size: 1.25rem !important;
76
+ color: var(--vp-c-text-2);
77
+ }
78
+
79
+ /* Feature cards */
80
+ .VPFeature {
81
+ border: 1px solid var(--vp-c-divider);
82
+ transition: all 0.3s ease;
83
+ }
84
+
85
+ .VPFeature:hover {
86
+ border-color: var(--neo-teal);
87
+ box-shadow: 0 4px 20px rgba(13, 148, 136, 0.15);
88
+ }
89
+
90
+ .VPFeature .icon {
91
+ font-size: 2rem;
92
+ }
93
+
94
+ /* Code blocks */
95
+ .vp-code-group .tabs label.active {
96
+ color: var(--neo-teal);
97
+ }
98
+
99
+ /* Custom badges */
100
+ .vp-badge.tip {
101
+ background-color: var(--neo-teal);
102
+ }
103
+
104
+ .vp-badge.warning {
105
+ background-color: var(--neo-orange);
106
+ }
107
+
108
+ /* Navigation active state */
109
+ .VPNavBarMenuLink.active,
110
+ .VPSidebarItem.is-active > .item > .link > .text {
111
+ color: var(--neo-teal) !important;
112
+ }
113
+
114
+ /* Custom container styles */
115
+ .custom-block.tip {
116
+ border-color: var(--neo-teal);
117
+ }
118
+
119
+ .custom-block.warning {
120
+ border-color: var(--neo-orange);
121
+ }
122
+
123
+ /* Table styling */
124
+ table {
125
+ border-collapse: collapse;
126
+ width: 100%;
127
+ }
128
+
129
+ th {
130
+ background-color: rgba(13, 148, 136, 0.1);
131
+ }
132
+
133
+ /* Gradient text utility */
134
+ .gradient-text {
135
+ background: linear-gradient(135deg, var(--neo-teal) 0%, var(--neo-orange) 100%);
136
+ -webkit-background-clip: text;
137
+ -webkit-text-fill-color: transparent;
138
+ background-clip: text;
139
+ }
140
+
141
+ /* Animation for hero */
142
+ @keyframes float {
143
+ 0%, 100% { transform: translateY(0); }
144
+ 50% { transform: translateY(-10px); }
145
+ }
146
+
147
+ .VPHero .VPImage img {
148
+ animation: float 3s ease-in-out infinite;
149
+ }
150
+
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Customize VitePress theme with Neo-Syringe colors
3
+ * Primary: Teal/Cyan (#0d9488)
4
+ * Accent: Orange (#f97316)
5
+ */
6
+ import { h } from 'vue'
7
+ import type { Theme } from 'vitepress'
8
+ import DefaultTheme from 'vitepress/theme'
9
+ import './custom.css'
10
+
11
+ export default {
12
+ extends: DefaultTheme,
13
+ Layout: () => {
14
+ return h(DefaultTheme.Layout, null, {})
15
+ },
16
+ } satisfies Theme
17
+
@@ -0,0 +1,274 @@
1
+ # Configuration
2
+
3
+ Configure Neo-Syringe in your project.
4
+
5
+ ## Build Plugin
6
+
7
+ ### Vite
8
+
9
+ ```typescript
10
+ // vite.config.ts
11
+ import { defineConfig } from 'vite';
12
+ import { neoSyringePlugin } from '@djodjonx/neo-syringe/plugin';
13
+
14
+ export default defineConfig({
15
+ plugins: [neoSyringePlugin.vite()]
16
+ });
17
+ ```
18
+
19
+ ### Rollup
20
+
21
+ ```typescript
22
+ // rollup.config.js
23
+ import { neoSyringePlugin } from '@djodjonx/neo-syringe/plugin';
24
+
25
+ export default {
26
+ input: 'src/main.ts',
27
+ output: {
28
+ file: 'dist/bundle.js',
29
+ format: 'esm'
30
+ },
31
+ plugins: [neoSyringePlugin.rollup()]
32
+ };
33
+ ```
34
+
35
+ ### Webpack
36
+
37
+ ```javascript
38
+ // webpack.config.js
39
+ const { webpack } = require('@djodjonx/neo-syringe/plugin');
40
+
41
+ module.exports = {
42
+ plugins: [webpack()]
43
+ };
44
+ ```
45
+
46
+ ### esbuild
47
+
48
+ ```typescript
49
+ // esbuild.config.js
50
+ import { neoSyringePlugin } from '@djodjonx/neo-syringe/plugin';
51
+ import esbuild from 'esbuild';
52
+
53
+ await esbuild.build({
54
+ entryPoints: ['src/main.ts'],
55
+ bundle: true,
56
+ outfile: 'dist/bundle.js',
57
+ plugins: [neoSyringePlugin.esbuild()]
58
+ });
59
+ ```
60
+
61
+ ### Rspack
62
+
63
+ ```javascript
64
+ // rspack.config.js
65
+ const { rspack } = require('@djodjonx/neo-syringe/plugin');
66
+
67
+ module.exports = {
68
+ plugins: [rspack()]
69
+ };
70
+ ```
71
+
72
+ ## TypeScript LSP Plugin
73
+
74
+ Add to `tsconfig.json` for IDE error detection:
75
+
76
+ ```json
77
+ {
78
+ "compilerOptions": {
79
+ "plugins": [
80
+ { "name": "@djodjonx/neo-syringe/lsp" }
81
+ ]
82
+ }
83
+ }
84
+ ```
85
+
86
+ ::: tip VS Code
87
+ Remember to select "Use Workspace Version" for TypeScript.
88
+ :::
89
+
90
+ ## BuilderConfig Options
91
+
92
+ ```typescript
93
+ defineBuilderConfig({
94
+ // Container name (for debugging)
95
+ name: 'AppContainer',
96
+
97
+ // List of injections
98
+ injections: [
99
+ { token: UserService },
100
+ { token: useInterface<ILogger>(), provider: ConsoleLogger }
101
+ ],
102
+
103
+ // Inherit from partial configs
104
+ extends: [loggingPartial, databasePartial],
105
+
106
+ // Parent container (Neo-Syringe or legacy)
107
+ useContainer: parentContainer
108
+ });
109
+ ```
110
+
111
+ ### name
112
+
113
+ Type: `string`
114
+
115
+ Optional. The container name appears in error messages.
116
+
117
+ ```typescript
118
+ defineBuilderConfig({
119
+ name: 'UserModule'
120
+ });
121
+
122
+ // Error: [UserModule] Service not found: XYZ
123
+ ```
124
+
125
+ ### injections
126
+
127
+ Type: `Injection[]`
128
+
129
+ Required. List of services to register.
130
+
131
+ ```typescript
132
+ defineBuilderConfig({
133
+ injections: [
134
+ // Class autowiring
135
+ { token: UserService },
136
+
137
+ // Interface binding
138
+ { token: useInterface<ILogger>(), provider: ConsoleLogger },
139
+
140
+ // Explicit provider
141
+ { token: BaseService, provider: ConcreteService },
142
+
143
+ // Factory
144
+ { token: useInterface<IConfig>(), provider: () => loadConfig() },
145
+
146
+ // Property token
147
+ { token: useProperty<string>(ApiService, 'apiUrl'), provider: () => 'http://...' },
148
+
149
+ // With lifecycle
150
+ { token: RequestContext, lifecycle: 'transient' },
151
+
152
+ // Scoped override
153
+ { token: useInterface<ILogger>(), provider: MockLogger, scoped: true }
154
+ ]
155
+ });
156
+ ```
157
+
158
+ ### extends
159
+
160
+ Type: `PartialConfig[]`
161
+
162
+ Optional. Inherit injections from partial configs.
163
+
164
+ ```typescript
165
+ const loggingPartial = definePartialConfig({
166
+ injections: [
167
+ { token: useInterface<ILogger>(), provider: ConsoleLogger }
168
+ ]
169
+ });
170
+
171
+ defineBuilderConfig({
172
+ extends: [loggingPartial],
173
+ injections: [
174
+ { token: UserService } // Can use ILogger
175
+ ]
176
+ });
177
+ ```
178
+
179
+ ### useContainer
180
+
181
+ Type: `Container | any`
182
+
183
+ Optional. Parent container for delegation.
184
+
185
+ ```typescript
186
+ // Neo-Syringe parent
187
+ defineBuilderConfig({
188
+ useContainer: sharedKernel,
189
+ injections: [...]
190
+ });
191
+
192
+ // Legacy container (tsyringe, etc.)
193
+ const legacy = declareContainerTokens<{...}>(tsyringeContainer);
194
+ defineBuilderConfig({
195
+ useContainer: legacy,
196
+ injections: [...]
197
+ });
198
+ ```
199
+
200
+ ## Injection Options
201
+
202
+ ```typescript
203
+ interface Injection<T> {
204
+ token: Token<T>;
205
+ provider?: Provider<T>;
206
+ useFactory?: boolean;
207
+ lifecycle?: 'singleton' | 'transient';
208
+ scoped?: boolean;
209
+ }
210
+ ```
211
+
212
+ ### token
213
+
214
+ Type: `Token<T>` (required)
215
+
216
+ What to register. Can be:
217
+
218
+ - Class constructor: `UserService`
219
+ - Interface token: `useInterface<ILogger>()`
220
+ - Property token: `useProperty<string>(ApiService, 'apiUrl')`
221
+
222
+ ### provider
223
+
224
+ Type: `Provider<T>`
225
+
226
+ What provides the instance. Can be:
227
+
228
+ - Class constructor: `ConsoleLogger`
229
+ - Factory function: `(container) => new Service()`
230
+
231
+ If omitted, the token itself is used (autowiring).
232
+
233
+ ### useFactory
234
+
235
+ Type: `boolean`
236
+
237
+ Force treating the provider as a factory function.
238
+
239
+ ```typescript
240
+ // Auto-detected (arrow function)
241
+ { provider: () => createService() }
242
+
243
+ // Explicit (regular function)
244
+ { provider: createService, useFactory: true }
245
+ ```
246
+
247
+ ### lifecycle
248
+
249
+ Type: `'singleton' | 'transient'`
250
+
251
+ Default: `'singleton'`
252
+
253
+ How instances are managed.
254
+
255
+ ```typescript
256
+ { token: UserService, lifecycle: 'singleton' } // One instance
257
+ { token: RequestContext, lifecycle: 'transient' } // New each time
258
+ ```
259
+
260
+ ### scoped
261
+
262
+ Type: `boolean`
263
+
264
+ Default: `false`
265
+
266
+ If `true`, resolve locally instead of delegating to parent.
267
+
268
+ ```typescript
269
+ // Override parent's ILogger with local MockLogger
270
+ { token: useInterface<ILogger>(), provider: MockLogger, scoped: true }
271
+ ```
272
+
273
+ See [Scoped Injections](/guide/scoped-injections) for details.
274
+