@buenojs/bueno 0.8.1 → 0.8.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.
- package/dist/cli/index.js +77 -7
- package/dist/index.js +28 -9
- package/package.json +1 -1
- package/src/cli/commands/new.ts +80 -5
- package/src/container/index.ts +2 -2
- package/src/modules/index.ts +27 -6
- package/tsconfig.json +3 -1
package/dist/cli/index.js
CHANGED
|
@@ -20,6 +20,10 @@ var __legacyDecorateClassTS = function(decorators, target, key, desc) {
|
|
|
20
20
|
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
21
21
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
22
22
|
};
|
|
23
|
+
var __legacyMetadataTS = (k, v) => {
|
|
24
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function")
|
|
25
|
+
return Reflect.metadata(k, v);
|
|
26
|
+
};
|
|
23
27
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
24
28
|
var __require = import.meta.require;
|
|
25
29
|
|
|
@@ -1328,9 +1332,10 @@ function validateProjectName(name) {
|
|
|
1328
1332
|
return true;
|
|
1329
1333
|
}
|
|
1330
1334
|
function getPackageJsonTemplate(config) {
|
|
1331
|
-
const dependencies = {
|
|
1332
|
-
|
|
1333
|
-
|
|
1335
|
+
const dependencies = {};
|
|
1336
|
+
if (!config.link) {
|
|
1337
|
+
dependencies["@buenojs/bueno"] = "^0.8.0";
|
|
1338
|
+
}
|
|
1334
1339
|
const devDependencies = {
|
|
1335
1340
|
"@types/bun": "latest",
|
|
1336
1341
|
typescript: "^5.3.0"
|
|
@@ -1405,8 +1410,44 @@ export class AppController {
|
|
|
1405
1410
|
constructor(private readonly appService: AppService) {}
|
|
1406
1411
|
|
|
1407
1412
|
@Get()
|
|
1408
|
-
|
|
1409
|
-
return
|
|
1413
|
+
hello() {
|
|
1414
|
+
return new Response(\`<html>
|
|
1415
|
+
<head>
|
|
1416
|
+
<title>Welcome to Bueno</title>
|
|
1417
|
+
<style>
|
|
1418
|
+
body { font-family: system-ui, sans-serif; max-width: 800px; margin: 50px auto; padding: 20px; }
|
|
1419
|
+
h1 { color: #2563eb; }
|
|
1420
|
+
code { background: #f3f4f6; padding: 2px 6px; border-radius: 4px; }
|
|
1421
|
+
pre { background: #f3f4f6; padding: 16px; border-radius: 8px; overflow-x: auto; }
|
|
1422
|
+
a { color: #2563eb; }
|
|
1423
|
+
</style>
|
|
1424
|
+
</head>
|
|
1425
|
+
<body>
|
|
1426
|
+
<h1>\uD83C\uDF89 Welcome to Bueno Framework!</h1>
|
|
1427
|
+
<p>Your Bun-native full-stack framework is running successfully.</p>
|
|
1428
|
+
|
|
1429
|
+
<h2>Getting Started</h2>
|
|
1430
|
+
<ul>
|
|
1431
|
+
<li>Edit <code>server/main.ts</code> to modify this app</li>
|
|
1432
|
+
<li>Add routes using the <code>@Get()</code>, <code>@Post()</code> decorators</li>
|
|
1433
|
+
<li>Create services with <code>@Injectable()</code> and inject them in controllers</li>
|
|
1434
|
+
</ul>
|
|
1435
|
+
|
|
1436
|
+
<h2>Documentation</h2>
|
|
1437
|
+
<p>Visit <a href="https://buenojs.dev">https://buenojs.dev</a> for full documentation.</p>
|
|
1438
|
+
|
|
1439
|
+
<h2>Quick Example</h2>
|
|
1440
|
+
<pre><code>@Controller('/api')
|
|
1441
|
+
class MyController {
|
|
1442
|
+
@Get('/users')
|
|
1443
|
+
getUsers() {
|
|
1444
|
+
return { users: [] };
|
|
1445
|
+
}
|
|
1446
|
+
}</code></pre>
|
|
1447
|
+
</body>
|
|
1448
|
+
</html>\`, {
|
|
1449
|
+
headers: { 'Content-Type': 'text/html; charset=utf-8' }
|
|
1450
|
+
});
|
|
1410
1451
|
}
|
|
1411
1452
|
|
|
1412
1453
|
@Get('health')
|
|
@@ -1669,6 +1710,7 @@ async function handleNew(args) {
|
|
|
1669
1710
|
const skipInstall = hasFlag(args, "skip-install");
|
|
1670
1711
|
const skipGit = hasFlag(args, "skip-git");
|
|
1671
1712
|
const docker = hasFlag(args, "docker");
|
|
1713
|
+
const link = hasFlag(args, "link");
|
|
1672
1714
|
const deployPlatforms = getOptionValues(args, "deploy");
|
|
1673
1715
|
const validPlatforms = ["render", "fly", "railway"];
|
|
1674
1716
|
const deploy = [];
|
|
@@ -1717,7 +1759,8 @@ async function handleNew(args) {
|
|
|
1717
1759
|
skipInstall,
|
|
1718
1760
|
skipGit,
|
|
1719
1761
|
docker,
|
|
1720
|
-
deploy
|
|
1762
|
+
deploy,
|
|
1763
|
+
link
|
|
1721
1764
|
};
|
|
1722
1765
|
const projectPath = joinPaths(process.cwd(), kebabCase(name));
|
|
1723
1766
|
if (await fileExists(projectPath)) {
|
|
@@ -1731,6 +1774,7 @@ async function handleNew(args) {
|
|
|
1731
1774
|
["Docker", docker ? colors.green("Yes") : colors.red("No")],
|
|
1732
1775
|
["Deploy", deploy.length > 0 ? colors.green(deploy.map(getDeployPlatformName).join(", ")) : colors.red("None")],
|
|
1733
1776
|
["Install dependencies", skipInstall ? colors.red("No") : colors.green("Yes")],
|
|
1777
|
+
["Use local package", link ? colors.green("Yes (bun link)") : colors.red("No")],
|
|
1734
1778
|
["Initialize git", skipGit ? colors.red("No") : colors.green("Yes")]
|
|
1735
1779
|
];
|
|
1736
1780
|
printTable(["Setting", "Value"], rows);
|
|
@@ -1755,6 +1799,25 @@ async function handleNew(args) {
|
|
|
1755
1799
|
} catch {
|
|
1756
1800
|
installSpinner.warn("Failed to install dependencies. Run `bun install` manually.");
|
|
1757
1801
|
}
|
|
1802
|
+
if (link) {
|
|
1803
|
+
cliConsole.subheader("Linking local @buenojs/bueno...");
|
|
1804
|
+
const linkSpinner = spinner("Running bun link @buenojs/bueno...");
|
|
1805
|
+
try {
|
|
1806
|
+
const proc = Bun.spawn(["bun", "link", "@buenojs/bueno"], {
|
|
1807
|
+
cwd: projectPath,
|
|
1808
|
+
stdout: "pipe",
|
|
1809
|
+
stderr: "pipe"
|
|
1810
|
+
});
|
|
1811
|
+
const exitCode = await proc.exited;
|
|
1812
|
+
if (exitCode === 0) {
|
|
1813
|
+
linkSpinner.success("Local @buenojs/bueno linked successfully");
|
|
1814
|
+
} else {
|
|
1815
|
+
linkSpinner.warn("Failed to link @buenojs/bueno. Make sure you have run `bun link` in the bueno directory first.");
|
|
1816
|
+
}
|
|
1817
|
+
} catch {
|
|
1818
|
+
linkSpinner.warn("Failed to link @buenojs/bueno. Make sure you have run `bun link` in the bueno directory first.");
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1758
1821
|
}
|
|
1759
1822
|
if (!skipGit) {
|
|
1760
1823
|
cliConsole.subheader("Initializing git repository...");
|
|
@@ -1835,6 +1898,12 @@ defineCommand({
|
|
|
1835
1898
|
default: false,
|
|
1836
1899
|
description: "Include Docker configuration (Dockerfile, docker-compose.yml)"
|
|
1837
1900
|
},
|
|
1901
|
+
{
|
|
1902
|
+
name: "link",
|
|
1903
|
+
type: "boolean",
|
|
1904
|
+
default: false,
|
|
1905
|
+
description: "Use local @buenojs/bueno via bun link (for development)"
|
|
1906
|
+
},
|
|
1838
1907
|
{
|
|
1839
1908
|
name: "deploy",
|
|
1840
1909
|
type: "string",
|
|
@@ -1860,7 +1929,8 @@ defineCommand({
|
|
|
1860
1929
|
"bueno new my-app --deploy render --deploy fly",
|
|
1861
1930
|
"bueno new my-app --docker --deploy render",
|
|
1862
1931
|
"bueno new my-app --docker --database postgresql --deploy render",
|
|
1863
|
-
"bueno new my-app -y"
|
|
1932
|
+
"bueno new my-app -y",
|
|
1933
|
+
"bueno new my-app --link"
|
|
1864
1934
|
]
|
|
1865
1935
|
}, handleNew);
|
|
1866
1936
|
|
package/dist/index.js
CHANGED
|
@@ -19,6 +19,10 @@ var __legacyDecorateClassTS = function(decorators, target, key, desc) {
|
|
|
19
19
|
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
20
20
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
21
21
|
};
|
|
22
|
+
var __legacyMetadataTS = (k, v) => {
|
|
23
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function")
|
|
24
|
+
return Reflect.metadata(k, v);
|
|
25
|
+
};
|
|
22
26
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
23
27
|
var __require = import.meta.require;
|
|
24
28
|
|
|
@@ -564,7 +568,7 @@ class ResolutionStack {
|
|
|
564
568
|
}
|
|
565
569
|
}
|
|
566
570
|
|
|
567
|
-
class
|
|
571
|
+
class Container2 {
|
|
568
572
|
providers = new Map;
|
|
569
573
|
resolutionStack = new ResolutionStack;
|
|
570
574
|
register(provider) {
|
|
@@ -684,7 +688,7 @@ class Container {
|
|
|
684
688
|
return Array.from(this.providers.keys());
|
|
685
689
|
}
|
|
686
690
|
createChild() {
|
|
687
|
-
const child = new
|
|
691
|
+
const child = new Container2;
|
|
688
692
|
for (const [token, resolved] of this.providers) {
|
|
689
693
|
if (resolved.provider.scope === "singleton") {
|
|
690
694
|
child.providers.set(token, resolved);
|
|
@@ -1901,7 +1905,10 @@ class ModuleLoader {
|
|
|
1901
1905
|
}
|
|
1902
1906
|
}
|
|
1903
1907
|
ModuleLoader = __legacyDecorateClassTS([
|
|
1904
|
-
Injectable2()
|
|
1908
|
+
Injectable2(),
|
|
1909
|
+
__legacyMetadataTS("design:paramtypes", [
|
|
1910
|
+
typeof Container === "undefined" ? Object : Container
|
|
1911
|
+
])
|
|
1905
1912
|
], ModuleLoader);
|
|
1906
1913
|
|
|
1907
1914
|
class LazyModuleRegistry {
|
|
@@ -2692,9 +2699,9 @@ function createInternalErrorResponse(exception) {
|
|
|
2692
2699
|
function Inject2(token) {
|
|
2693
2700
|
return (target, propertyKey, parameterIndex) => {
|
|
2694
2701
|
const targetObj = target;
|
|
2695
|
-
const existingTokens =
|
|
2702
|
+
const existingTokens = getContainerMetadata(targetObj, "inject:tokens") ?? [];
|
|
2696
2703
|
existingTokens[parameterIndex] = token;
|
|
2697
|
-
|
|
2704
|
+
setContainerMetadata(targetObj, "inject:tokens", existingTokens);
|
|
2698
2705
|
};
|
|
2699
2706
|
}
|
|
2700
2707
|
function createMethodDecorator(method) {
|
|
@@ -2748,7 +2755,13 @@ class AppModule {
|
|
|
2748
2755
|
}
|
|
2749
2756
|
}
|
|
2750
2757
|
if (metadata.providers) {
|
|
2751
|
-
|
|
2758
|
+
const normalizedProviders = metadata.providers.map((p) => {
|
|
2759
|
+
if (typeof p === "function" && !p.token) {
|
|
2760
|
+
return { token: p, useClass: p };
|
|
2761
|
+
}
|
|
2762
|
+
return p;
|
|
2763
|
+
});
|
|
2764
|
+
this.providers.push(...normalizedProviders);
|
|
2752
2765
|
}
|
|
2753
2766
|
if (metadata.controllers) {
|
|
2754
2767
|
this.controllers.push(...metadata.controllers);
|
|
@@ -2787,7 +2800,7 @@ class Application {
|
|
|
2787
2800
|
moduleLoader;
|
|
2788
2801
|
loadedLazyModules = new Set;
|
|
2789
2802
|
constructor(moduleClass) {
|
|
2790
|
-
this.container = new
|
|
2803
|
+
this.container = new Container2;
|
|
2791
2804
|
this.router = new Router;
|
|
2792
2805
|
this.appModule = new AppModule(moduleClass);
|
|
2793
2806
|
this.lifecycleManager = new LifecycleHookManager;
|
|
@@ -2834,7 +2847,13 @@ class Application {
|
|
|
2834
2847
|
registerController(controllerClass) {
|
|
2835
2848
|
const basePath = getMetadata(controllerClass, "path") ?? "";
|
|
2836
2849
|
const routes = getPrototypeMetadata(controllerClass.prototype, "routes") ?? [];
|
|
2837
|
-
|
|
2850
|
+
let injectTokens = getContainerMetadata(controllerClass, "inject:tokens") ?? [];
|
|
2851
|
+
if (injectTokens.length === 0 && typeof Reflect !== "undefined" && typeof Reflect.getMetadata === "function") {
|
|
2852
|
+
const paramTypes = Reflect.getMetadata("design:paramtypes", controllerClass);
|
|
2853
|
+
if (paramTypes) {
|
|
2854
|
+
injectTokens = paramTypes.map((paramType) => paramType);
|
|
2855
|
+
}
|
|
2856
|
+
}
|
|
2838
2857
|
const deps = injectTokens.map((tokenOrRef) => {
|
|
2839
2858
|
const token = isForwardRef(tokenOrRef) ? resolveForwardRef(tokenOrRef) : tokenOrRef;
|
|
2840
2859
|
return this.container.resolve(token);
|
|
@@ -9004,7 +9023,7 @@ export {
|
|
|
9004
9023
|
Database,
|
|
9005
9024
|
Controller,
|
|
9006
9025
|
Context,
|
|
9007
|
-
Container,
|
|
9026
|
+
Container2 as Container,
|
|
9008
9027
|
ConfigManager,
|
|
9009
9028
|
Cache,
|
|
9010
9029
|
CSRF,
|
package/package.json
CHANGED
package/src/cli/commands/new.ts
CHANGED
|
@@ -58,6 +58,7 @@ interface ProjectConfig {
|
|
|
58
58
|
skipGit: boolean;
|
|
59
59
|
docker: boolean;
|
|
60
60
|
deploy: DeployPlatform[];
|
|
61
|
+
link: boolean;
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
/**
|
|
@@ -87,9 +88,13 @@ function validateProjectName(name: string): boolean | string {
|
|
|
87
88
|
* Get package.json template
|
|
88
89
|
*/
|
|
89
90
|
function getPackageJsonTemplate(config: ProjectConfig): string {
|
|
90
|
-
const dependencies: Record<string, string> = {
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
const dependencies: Record<string, string> = {};
|
|
92
|
+
|
|
93
|
+
// If using link, don't add @buenojs/bueno to dependencies
|
|
94
|
+
// It will be linked from the local version
|
|
95
|
+
if (!config.link) {
|
|
96
|
+
dependencies['@buenojs/bueno'] = '^0.8.0';
|
|
97
|
+
}
|
|
93
98
|
|
|
94
99
|
const devDependencies: Record<string, string> = {
|
|
95
100
|
'@types/bun': 'latest',
|
|
@@ -186,8 +191,44 @@ export class AppController {
|
|
|
186
191
|
constructor(private readonly appService: AppService) {}
|
|
187
192
|
|
|
188
193
|
@Get()
|
|
189
|
-
|
|
190
|
-
return
|
|
194
|
+
hello() {
|
|
195
|
+
return new Response(\`<html>
|
|
196
|
+
<head>
|
|
197
|
+
<title>Welcome to Bueno</title>
|
|
198
|
+
<style>
|
|
199
|
+
body { font-family: system-ui, sans-serif; max-width: 800px; margin: 50px auto; padding: 20px; }
|
|
200
|
+
h1 { color: #2563eb; }
|
|
201
|
+
code { background: #f3f4f6; padding: 2px 6px; border-radius: 4px; }
|
|
202
|
+
pre { background: #f3f4f6; padding: 16px; border-radius: 8px; overflow-x: auto; }
|
|
203
|
+
a { color: #2563eb; }
|
|
204
|
+
</style>
|
|
205
|
+
</head>
|
|
206
|
+
<body>
|
|
207
|
+
<h1>🎉 Welcome to Bueno Framework!</h1>
|
|
208
|
+
<p>Your Bun-native full-stack framework is running successfully.</p>
|
|
209
|
+
|
|
210
|
+
<h2>Getting Started</h2>
|
|
211
|
+
<ul>
|
|
212
|
+
<li>Edit <code>server/main.ts</code> to modify this app</li>
|
|
213
|
+
<li>Add routes using the <code>@Get()</code>, <code>@Post()</code> decorators</li>
|
|
214
|
+
<li>Create services with <code>@Injectable()</code> and inject them in controllers</li>
|
|
215
|
+
</ul>
|
|
216
|
+
|
|
217
|
+
<h2>Documentation</h2>
|
|
218
|
+
<p>Visit <a href="https://buenojs.dev">https://buenojs.dev</a> for full documentation.</p>
|
|
219
|
+
|
|
220
|
+
<h2>Quick Example</h2>
|
|
221
|
+
<pre><code>@Controller('/api')
|
|
222
|
+
class MyController {
|
|
223
|
+
@Get('/users')
|
|
224
|
+
getUsers() {
|
|
225
|
+
return { users: [] };
|
|
226
|
+
}
|
|
227
|
+
}</code></pre>
|
|
228
|
+
</body>
|
|
229
|
+
</html>\`, {
|
|
230
|
+
headers: { 'Content-Type': 'text/html; charset=utf-8' }
|
|
231
|
+
});
|
|
191
232
|
}
|
|
192
233
|
|
|
193
234
|
@Get('health')
|
|
@@ -554,6 +595,7 @@ async function handleNew(args: ParsedArgs): Promise<void> {
|
|
|
554
595
|
const skipInstall = hasFlag(args, 'skip-install');
|
|
555
596
|
const skipGit = hasFlag(args, 'skip-git');
|
|
556
597
|
const docker = hasFlag(args, 'docker');
|
|
598
|
+
const link = hasFlag(args, 'link');
|
|
557
599
|
|
|
558
600
|
// Get deployment platforms (can be specified multiple times)
|
|
559
601
|
const deployPlatforms = getOptionValues(args, 'deploy');
|
|
@@ -628,6 +670,7 @@ async function handleNew(args: ParsedArgs): Promise<void> {
|
|
|
628
670
|
skipGit,
|
|
629
671
|
docker,
|
|
630
672
|
deploy,
|
|
673
|
+
link,
|
|
631
674
|
};
|
|
632
675
|
|
|
633
676
|
// Check if directory exists
|
|
@@ -649,6 +692,7 @@ async function handleNew(args: ParsedArgs): Promise<void> {
|
|
|
649
692
|
['Docker', docker ? colors.green('Yes') : colors.red('No')],
|
|
650
693
|
['Deploy', deploy.length > 0 ? colors.green(deploy.map(getDeployPlatformName).join(', ')) : colors.red('None')],
|
|
651
694
|
['Install dependencies', skipInstall ? colors.red('No') : colors.green('Yes')],
|
|
695
|
+
['Use local package', link ? colors.green('Yes (bun link)') : colors.red('No')],
|
|
652
696
|
['Initialize git', skipGit ? colors.red('No') : colors.green('Yes')],
|
|
653
697
|
];
|
|
654
698
|
|
|
@@ -681,6 +725,30 @@ async function handleNew(args: ParsedArgs): Promise<void> {
|
|
|
681
725
|
} catch {
|
|
682
726
|
installSpinner.warn('Failed to install dependencies. Run `bun install` manually.');
|
|
683
727
|
}
|
|
728
|
+
|
|
729
|
+
// Link local @buenojs/bueno if --link flag is set
|
|
730
|
+
if (link) {
|
|
731
|
+
cliConsole.subheader('Linking local @buenojs/bueno...');
|
|
732
|
+
const linkSpinner = spinner('Running bun link @buenojs/bueno...');
|
|
733
|
+
|
|
734
|
+
try {
|
|
735
|
+
const proc = Bun.spawn(['bun', 'link', '@buenojs/bueno'], {
|
|
736
|
+
cwd: projectPath,
|
|
737
|
+
stdout: 'pipe',
|
|
738
|
+
stderr: 'pipe',
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
const exitCode = await proc.exited;
|
|
742
|
+
|
|
743
|
+
if (exitCode === 0) {
|
|
744
|
+
linkSpinner.success('Local @buenojs/bueno linked successfully');
|
|
745
|
+
} else {
|
|
746
|
+
linkSpinner.warn('Failed to link @buenojs/bueno. Make sure you have run `bun link` in the bueno directory first.');
|
|
747
|
+
}
|
|
748
|
+
} catch {
|
|
749
|
+
linkSpinner.warn('Failed to link @buenojs/bueno. Make sure you have run `bun link` in the bueno directory first.');
|
|
750
|
+
}
|
|
751
|
+
}
|
|
684
752
|
}
|
|
685
753
|
|
|
686
754
|
// Initialize git
|
|
@@ -772,6 +840,12 @@ defineCommand(
|
|
|
772
840
|
default: false,
|
|
773
841
|
description: 'Include Docker configuration (Dockerfile, docker-compose.yml)',
|
|
774
842
|
},
|
|
843
|
+
{
|
|
844
|
+
name: 'link',
|
|
845
|
+
type: 'boolean',
|
|
846
|
+
default: false,
|
|
847
|
+
description: 'Use local @buenojs/bueno via bun link (for development)',
|
|
848
|
+
},
|
|
775
849
|
{
|
|
776
850
|
name: 'deploy',
|
|
777
851
|
type: 'string',
|
|
@@ -798,6 +872,7 @@ defineCommand(
|
|
|
798
872
|
'bueno new my-app --docker --deploy render',
|
|
799
873
|
'bueno new my-app --docker --database postgresql --deploy render',
|
|
800
874
|
'bueno new my-app -y',
|
|
875
|
+
'bueno new my-app --link',
|
|
801
876
|
],
|
|
802
877
|
},
|
|
803
878
|
handleNew,
|
package/src/container/index.ts
CHANGED
|
@@ -382,5 +382,5 @@ export function Inject(token: Token | ForwardRef<Token>): ParameterDecorator {
|
|
|
382
382
|
};
|
|
383
383
|
}
|
|
384
384
|
|
|
385
|
-
// Export getter for use by modules
|
|
386
|
-
export { getContainerMetadata as getInjectTokens };
|
|
385
|
+
// Export getter and setter for use by modules
|
|
386
|
+
export { getContainerMetadata as getInjectTokens, setContainerMetadata, getContainerMetadata };
|
package/src/modules/index.ts
CHANGED
|
@@ -14,6 +14,8 @@ import {
|
|
|
14
14
|
isForwardRef,
|
|
15
15
|
resolveForwardRef,
|
|
16
16
|
getInjectTokens,
|
|
17
|
+
setContainerMetadata,
|
|
18
|
+
getContainerMetadata,
|
|
17
19
|
} from "../container";
|
|
18
20
|
import {
|
|
19
21
|
type LazyModuleLoader,
|
|
@@ -162,11 +164,11 @@ export function Inject(token: Token | ForwardRef<Token>): ParameterDecorator {
|
|
|
162
164
|
propertyKey: string | symbol | undefined,
|
|
163
165
|
parameterIndex: number,
|
|
164
166
|
) => {
|
|
165
|
-
const targetObj = target as
|
|
167
|
+
const targetObj = target as object;
|
|
166
168
|
const existingTokens: Array<Token | ForwardRef<Token>> =
|
|
167
|
-
|
|
169
|
+
getContainerMetadata<Array<Token | ForwardRef<Token>>>(targetObj, "inject:tokens") ?? [];
|
|
168
170
|
existingTokens[parameterIndex] = token;
|
|
169
|
-
|
|
171
|
+
setContainerMetadata(targetObj, "inject:tokens", existingTokens);
|
|
170
172
|
};
|
|
171
173
|
}
|
|
172
174
|
|
|
@@ -246,9 +248,16 @@ export class AppModule {
|
|
|
246
248
|
}
|
|
247
249
|
}
|
|
248
250
|
|
|
249
|
-
// Add providers
|
|
251
|
+
// Add providers (normalize class references to provider objects)
|
|
250
252
|
if (metadata.providers) {
|
|
251
|
-
|
|
253
|
+
const normalizedProviders = metadata.providers.map(p => {
|
|
254
|
+
// If it's a class constructor (function) without token, normalize it
|
|
255
|
+
if (typeof p === 'function' && !p.token) {
|
|
256
|
+
return { token: p, useClass: p };
|
|
257
|
+
}
|
|
258
|
+
return p;
|
|
259
|
+
});
|
|
260
|
+
this.providers.push(...normalizedProviders);
|
|
252
261
|
}
|
|
253
262
|
|
|
254
263
|
// Add controllers
|
|
@@ -475,8 +484,20 @@ export class Application {
|
|
|
475
484
|
>(controllerClass.prototype, "routes") ?? [];
|
|
476
485
|
|
|
477
486
|
// Create controller instance
|
|
478
|
-
|
|
487
|
+
// First, check for explicit injection tokens from @Inject decorator
|
|
488
|
+
let injectTokens =
|
|
479
489
|
getInjectTokens<Array<Token | ForwardRef<Token>>>(controllerClass, "inject:tokens") ?? [];
|
|
490
|
+
|
|
491
|
+
// If no explicit tokens, try to use TypeScript's design:paramtypes metadata
|
|
492
|
+
// This requires the reflect-metadata polyfill to be imported by the user
|
|
493
|
+
if (injectTokens.length === 0 && typeof Reflect !== 'undefined' && typeof Reflect.getMetadata === 'function') {
|
|
494
|
+
const paramTypes = Reflect.getMetadata('design:paramtypes', controllerClass) as Array<new (...args: unknown[]) => unknown> | undefined;
|
|
495
|
+
if (paramTypes) {
|
|
496
|
+
// Use the constructor parameter types as injection tokens
|
|
497
|
+
injectTokens = paramTypes.map((paramType) => paramType as unknown as Token);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
480
501
|
const deps = injectTokens.map((tokenOrRef) => {
|
|
481
502
|
// Resolve forward reference if needed
|
|
482
503
|
const token = isForwardRef(tokenOrRef) ? resolveForwardRef(tokenOrRef) : tokenOrRef;
|
package/tsconfig.json
CHANGED