@hestjs/core
Advanced tools
| /** | ||
| * 应用启动钩子系统 | ||
| * | ||
| * 这是一个通用的钩子系统,允许外部包注册自己的初始化逻辑 | ||
| * 而不会让 core 包与特定的外部包产生耦合 | ||
| */ | ||
| export type ApplicationHook = (container: any) => Promise<void> | void; | ||
| /** | ||
| * 应用钩子管理器 | ||
| */ | ||
| export declare class ApplicationHooks { | ||
| private static instance; | ||
| private hooks; | ||
| private constructor(); | ||
| static getInstance(): ApplicationHooks; | ||
| /** | ||
| * 注册应用启动钩子 | ||
| */ | ||
| registerHook(hook: ApplicationHook): void; | ||
| /** | ||
| * 执行所有注册的钩子 | ||
| */ | ||
| executeHooks(container: any): Promise<void>; | ||
| /** | ||
| * 清空所有钩子 | ||
| */ | ||
| clearHooks(): void; | ||
| } | ||
| //# sourceMappingURL=application-hooks.d.ts.map |
| {"version":3,"file":"application-hooks.d.ts","sourceRoot":"","sources":["../../src/application/application-hooks.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,SAAS,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAEvE;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAmB;IAC1C,OAAO,CAAC,KAAK,CAAyB;IAEtC,OAAO;IAEP,MAAM,CAAC,WAAW,IAAI,gBAAgB;IAOtC;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI;IAIzC;;OAEG;IACG,YAAY,CAAC,SAAS,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAUjD;;OAEG;IACH,UAAU,IAAI,IAAI;CAGnB"} |
| "use strict"; | ||
| /** | ||
| * 应用启动钩子系统 | ||
| * | ||
| * 这是一个通用的钩子系统,允许外部包注册自己的初始化逻辑 | ||
| * 而不会让 core 包与特定的外部包产生耦合 | ||
| */ | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.ApplicationHooks = void 0; | ||
| /** | ||
| * 应用钩子管理器 | ||
| */ | ||
| class ApplicationHooks { | ||
| static instance; | ||
| hooks = []; | ||
| constructor() { } | ||
| static getInstance() { | ||
| if (!ApplicationHooks.instance) { | ||
| ApplicationHooks.instance = new ApplicationHooks(); | ||
| } | ||
| return ApplicationHooks.instance; | ||
| } | ||
| /** | ||
| * 注册应用启动钩子 | ||
| */ | ||
| registerHook(hook) { | ||
| this.hooks.push(hook); | ||
| } | ||
| /** | ||
| * 执行所有注册的钩子 | ||
| */ | ||
| async executeHooks(container) { | ||
| for (const hook of this.hooks) { | ||
| try { | ||
| await hook(container); | ||
| } | ||
| catch (error) { | ||
| console.warn('Failed to execute application hook:', error); | ||
| } | ||
| } | ||
| } | ||
| /** | ||
| * 清空所有钩子 | ||
| */ | ||
| clearHooks() { | ||
| this.hooks = []; | ||
| } | ||
| } | ||
| exports.ApplicationHooks = ApplicationHooks; | ||
| //# sourceMappingURL=application-hooks.js.map |
| {"version":3,"file":"application-hooks.js","sourceRoot":"","sources":["../../src/application/application-hooks.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAIH;;GAEG;AACH,MAAa,gBAAgB;IACnB,MAAM,CAAC,QAAQ,CAAmB;IAClC,KAAK,GAAsB,EAAE,CAAC;IAEtC,gBAAuB,CAAC;IAExB,MAAM,CAAC,WAAW;QAChB,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,CAAC;YAC/B,gBAAgB,CAAC,QAAQ,GAAG,IAAI,gBAAgB,EAAE,CAAC;QACrD,CAAC;QACD,OAAO,gBAAgB,CAAC,QAAQ,CAAC;IACnC,CAAC;IAED;;OAEG;IACH,YAAY,CAAC,IAAqB;QAChC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,YAAY,CAAC,SAAc;QAC/B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC9B,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,SAAS,CAAC,CAAC;YACxB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,IAAI,CAAC,qCAAqC,EAAE,KAAK,CAAC,CAAC;YAC7D,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACH,UAAU;QACR,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;IAClB,CAAC;CACF;AAvCD,4CAuCC"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"application-factory.d.ts","sourceRoot":"","sources":["../../src/application/application-factory.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAG7D;;GAEG;AACH,qBAAa,WAAW;IACtB;;OAEG;WACU,MAAM,CAAC,WAAW,EAAE,GAAG,GAAG,OAAO,CAAC,uBAAuB,CAAC;IA0BvE;;OAEG;mBACkB,gBAAgB;CAgDtC"} | ||
| {"version":3,"file":"application-factory.d.ts","sourceRoot":"","sources":["../../src/application/application-factory.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAI7D;;GAEG;AACH,qBAAa,WAAW;IACtB;;OAEG;WACU,MAAM,CAAC,WAAW,EAAE,GAAG,GAAG,OAAO,CAAC,uBAAuB,CAAC;IA6BvE;;OAEG;mBACkB,gBAAgB;CAgDtC"} |
@@ -9,2 +9,3 @@ "use strict"; | ||
| const hest_application_1 = require("./hest-application"); | ||
| const application_hooks_1 = require("./application-hooks"); | ||
| const logger_1 = require("@hestjs/logger"); | ||
@@ -35,2 +36,4 @@ /** | ||
| } | ||
| // 执行所有注册的应用启动钩子 | ||
| await application_hooks_1.ApplicationHooks.getInstance().executeHooks(container); | ||
| return appInstance; | ||
@@ -47,3 +50,3 @@ } | ||
| // 注册模块自身 | ||
| container.register(moduleClass, moduleClass); | ||
| container.register(moduleClass, moduleClass, 'module'); | ||
| // 注册提供者 | ||
@@ -54,5 +57,5 @@ if (moduleMetadata.providers) { | ||
| // 注册类本身作为令牌 | ||
| container.register(provider, provider); | ||
| container.register(provider, provider, 'provider'); | ||
| // 同时注册类名字符串作为令牌,以支持 @Inject('ClassName') 语法 | ||
| container.register(provider.name, provider); | ||
| container.register(provider.name, provider, 'provider'); | ||
| } | ||
@@ -68,3 +71,3 @@ else { | ||
| if (metadata_scanner_1.MetadataScanner.isController(controller)) { | ||
| container.register(controller, controller); | ||
| container.register(controller, controller, 'controller'); | ||
| } | ||
@@ -71,0 +74,0 @@ else { |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"application-factory.js","sourceRoot":"","sources":["../../src/application/application-factory.ts"],"names":[],"mappings":"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"} | ||
| {"version":3,"file":"application-factory.js","sourceRoot":"","sources":["../../src/application/application-factory.ts"],"names":[],"mappings":"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"} |
@@ -0,3 +1,4 @@ | ||
| export * from './application-factory'; | ||
| export * from './hest-application'; | ||
| export * from './application-factory'; | ||
| export * from './application-hooks'; | ||
| //# sourceMappingURL=index.d.ts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/application/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,uBAAuB,CAAC"} | ||
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/application/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC"} |
@@ -17,4 +17,5 @@ "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| __exportStar(require("./application-factory"), exports); | ||
| __exportStar(require("./hest-application"), exports); | ||
| __exportStar(require("./application-factory"), exports); | ||
| __exportStar(require("./application-hooks"), exports); | ||
| //# sourceMappingURL=index.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/application/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,qDAAmC;AACnC,wDAAsC"} | ||
| {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/application/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,wDAAsC;AACtC,qDAAmC;AACnC,sDAAoC"} |
| import "reflect-metadata"; | ||
| import { DependencyContainer, InjectionToken } from "tsyringe"; | ||
| import type { InjectableMetadata, ControllerMetadata, ModuleMetadata } from "../interfaces/metadata"; | ||
| import type { ControllerConstructor } from "../interfaces/router"; | ||
| import { Scope } from "../utils/constants"; | ||
| declare global { | ||
@@ -9,2 +12,19 @@ namespace Reflect { | ||
| /** | ||
| * 逻辑容器项类型 | ||
| */ | ||
| export interface LogicalContainerItem<T = any> { | ||
| token: InjectionToken<T>; | ||
| provider: T; | ||
| type: 'controller' | 'provider' | 'module'; | ||
| metadata?: ControllerMetadata | InjectableMetadata | ModuleMetadata; | ||
| scope?: Scope; | ||
| } | ||
| /** | ||
| * 控制器容器项特化类型 | ||
| */ | ||
| export interface ControllerContainerItem extends LogicalContainerItem<ControllerConstructor> { | ||
| type: 'controller'; | ||
| metadata?: ControllerMetadata; | ||
| } | ||
| /** | ||
| * HestJS DI 容器封装 | ||
@@ -15,2 +35,3 @@ */ | ||
| private container; | ||
| private logicalContainer; | ||
| constructor(); | ||
@@ -24,3 +45,3 @@ /** | ||
| */ | ||
| register<T>(token: InjectionToken<T>, provider: any): void; | ||
| register<T>(token: InjectionToken<T>, provider: any, type?: 'controller' | 'provider' | 'module'): void; | ||
| /** | ||
@@ -50,3 +71,19 @@ * 注册实例 | ||
| getContainer(): DependencyContainer; | ||
| /** | ||
| * 获取逻辑容器中的所有项 | ||
| */ | ||
| getLogicalContainer(): Map<InjectionToken<any>, LogicalContainerItem>; | ||
| /** | ||
| * 获取指定类型的所有项 | ||
| */ | ||
| getItemsByType(type: 'controller' | 'provider' | 'module'): LogicalContainerItem[]; | ||
| /** | ||
| * 获取所有控制器 | ||
| */ | ||
| getAllControllers(): ControllerContainerItem[]; | ||
| /** | ||
| * 提取元数据信息 | ||
| */ | ||
| private extractMetadata; | ||
| } | ||
| //# sourceMappingURL=container.d.ts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../../src/container/container.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EACL,mBAAmB,EACnB,cAAc,EAEf,MAAM,UAAU,CAAC;AAKlB,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,OAAO,CAAC;QAChB,SAAS,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,GAAG,CAAC;KACjF;CACF;AAED;;GAEG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAY;IACnC,OAAO,CAAC,SAAS,CAAsB;;IAMvC;;OAEG;IACH,MAAM,CAAC,WAAW,IAAI,SAAS;IAO/B;;OAEG;IACH,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,GAAG,IAAI;IAgB1D;;OAEG;IACH,gBAAgB,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI;IAIhE;;OAEG;IACH,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC;IAIvC;;OAEG;IACH,YAAY,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,OAAO;IAIlD;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,WAAW,IAAI,SAAS;IAMxB;;OAEG;IACH,YAAY,IAAI,mBAAmB;CAGpC"} | ||
| {"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../../src/container/container.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EACL,mBAAmB,EACnB,cAAc,EAEf,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACrG,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAiB,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAG1D,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,OAAO,CAAC;QAChB,SAAS,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,GAAG,CAAC;KACjF;CACF;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB,CAAC,CAAC,GAAG,GAAG;IAC3C,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC;IACzB,QAAQ,EAAE,CAAC,CAAC;IACZ,IAAI,EAAE,YAAY,GAAG,UAAU,GAAG,QAAQ,CAAC;IAC3C,QAAQ,CAAC,EAAE,kBAAkB,GAAG,kBAAkB,GAAG,cAAc,CAAC;IACpE,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,uBAAwB,SAAQ,oBAAoB,CAAC,qBAAqB,CAAC;IAC1F,IAAI,EAAE,YAAY,CAAC;IACnB,QAAQ,CAAC,EAAE,kBAAkB,CAAC;CAC/B;AAED;;GAEG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAY;IACnC,OAAO,CAAC,SAAS,CAAsB;IACvC,OAAO,CAAC,gBAAgB,CAA6D;;IAMrF;;OAEG;IACH,MAAM,CAAC,WAAW,IAAI,SAAS;IAO/B;;OAEG;IACH,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,GAAE,YAAY,GAAG,UAAU,GAAG,QAAqB,GAAG,IAAI;IA0BnH;;OAEG;IACH,gBAAgB,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI;IAIhE;;OAEG;IACH,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC;IAIvC;;OAEG;IACH,YAAY,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,OAAO;IAIlD;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,WAAW,IAAI,SAAS;IAMxB;;OAEG;IACH,YAAY,IAAI,mBAAmB;IAInC;;OAEG;IACH,mBAAmB,IAAI,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,oBAAoB,CAAC;IAIrE;;OAEG;IACH,cAAc,CAAC,IAAI,EAAE,YAAY,GAAG,UAAU,GAAG,QAAQ,GAAG,oBAAoB,EAAE;IAIlF;;OAEG;IACH,iBAAiB,IAAI,uBAAuB,EAAE;IAI9C;;OAEG;IACH,OAAO,CAAC,eAAe;CAYxB"} |
@@ -13,2 +13,3 @@ "use strict"; | ||
| container; | ||
| logicalContainer = new Map(); | ||
| constructor() { | ||
@@ -29,4 +30,13 @@ this.container = tsyringe_1.container.createChildContainer(); | ||
| */ | ||
| register(token, provider) { | ||
| register(token, provider, type = 'provider') { | ||
| const metadata = Reflect.getMetadata(constants_1.METADATA_KEYS.INJECTABLE, provider) || {}; | ||
| // 保存到逻辑容器 | ||
| const logicalItem = { | ||
| token, | ||
| provider, | ||
| type, | ||
| metadata: this.extractMetadata(provider, type), | ||
| scope: metadata.scope | ||
| }; | ||
| this.logicalContainer.set(token, logicalItem); | ||
| switch (metadata.scope) { | ||
@@ -81,4 +91,37 @@ case constants_1.Scope.SINGLETON: | ||
| } | ||
| /** | ||
| * 获取逻辑容器中的所有项 | ||
| */ | ||
| getLogicalContainer() { | ||
| return this.logicalContainer; | ||
| } | ||
| /** | ||
| * 获取指定类型的所有项 | ||
| */ | ||
| getItemsByType(type) { | ||
| return Array.from(this.logicalContainer.values()).filter(item => item.type === type); | ||
| } | ||
| /** | ||
| * 获取所有控制器 | ||
| */ | ||
| getAllControllers() { | ||
| return this.getItemsByType('controller'); | ||
| } | ||
| /** | ||
| * 提取元数据信息 | ||
| */ | ||
| extractMetadata(provider, type) { | ||
| switch (type) { | ||
| case 'controller': | ||
| return Reflect.getMetadata(constants_1.METADATA_KEYS.CONTROLLER, provider); | ||
| case 'module': | ||
| return Reflect.getMetadata(constants_1.METADATA_KEYS.MODULE, provider); | ||
| case 'provider': | ||
| return Reflect.getMetadata(constants_1.METADATA_KEYS.INJECTABLE, provider); | ||
| default: | ||
| return null; | ||
| } | ||
| } | ||
| } | ||
| exports.Container = Container; | ||
| //# sourceMappingURL=container.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"container.js","sourceRoot":"","sources":["../../src/container/container.ts"],"names":[],"mappings":";;;AAAA,4BAA0B;AAC1B,uCAIkB;AAElB,kDAA0D;AAS1D;;GAEG;AACH,MAAa,SAAS;IACZ,MAAM,CAAC,QAAQ,CAAY;IAC3B,SAAS,CAAsB;IAEvC;QACE,IAAI,CAAC,SAAS,GAAG,oBAAiB,CAAC,oBAAoB,EAAE,CAAC;IAC5D,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,WAAW;QAChB,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC;YACxB,SAAS,CAAC,QAAQ,GAAG,IAAI,SAAS,EAAE,CAAC;QACvC,CAAC;QACD,OAAO,SAAS,CAAC,QAAQ,CAAC;IAC5B,CAAC;IAED;;OAEG;IACH,QAAQ,CAAI,KAAwB,EAAE,QAAa;QACjD,MAAM,QAAQ,GACZ,OAAO,CAAC,WAAW,CAAC,yBAAa,CAAC,UAAU,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC;QAEhE,QAAQ,QAAQ,CAAC,KAAK,EAAE,CAAC;YACvB,KAAK,iBAAK,CAAC,SAAS;gBAClB,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;gBAClD,MAAM;YACR,KAAK,iBAAK,CAAC,SAAS;gBAClB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;gBACvD,MAAM;YACR;gBACE,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;IAED;;OAEG;IACH,gBAAgB,CAAI,KAAwB,EAAE,QAAW;QACvD,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IACnD,CAAC;IAED;;OAEG;IACH,OAAO,CAAI,KAAwB;QACjC,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACvC,CAAC;IAED;;OAEG;IACH,YAAY,CAAI,KAAwB;QACtC,OAAO,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,SAAS,CAAC,cAAc,EAAE,CAAC;IAClC,CAAC;IAED;;OAEG;IACH,WAAW;QACT,MAAM,KAAK,GAAG,IAAI,SAAS,EAAE,CAAC;QAC9B,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,oBAAoB,EAAE,CAAC;QACxD,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACH,YAAY;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;CACF;AAhFD,8BAgFC"} | ||
| {"version":3,"file":"container.js","sourceRoot":"","sources":["../../src/container/container.ts"],"names":[],"mappings":";;;AAAA,4BAA0B;AAC1B,uCAIkB;AAGlB,kDAA0D;AA4B1D;;GAEG;AACH,MAAa,SAAS;IACZ,MAAM,CAAC,QAAQ,CAAY;IAC3B,SAAS,CAAsB;IAC/B,gBAAgB,GAAmD,IAAI,GAAG,EAAE,CAAC;IAErF;QACE,IAAI,CAAC,SAAS,GAAG,oBAAiB,CAAC,oBAAoB,EAAE,CAAC;IAC5D,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,WAAW;QAChB,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC;YACxB,SAAS,CAAC,QAAQ,GAAG,IAAI,SAAS,EAAE,CAAC;QACvC,CAAC;QACD,OAAO,SAAS,CAAC,QAAQ,CAAC;IAC5B,CAAC;IAED;;OAEG;IACH,QAAQ,CAAI,KAAwB,EAAE,QAAa,EAAE,OAA6C,UAAU;QAC1G,MAAM,QAAQ,GACZ,OAAO,CAAC,WAAW,CAAC,yBAAa,CAAC,UAAU,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC;QAEhE,UAAU;QACV,MAAM,WAAW,GAAyB;YACxC,KAAK;YACL,QAAQ;YACR,IAAI;YACJ,QAAQ,EAAE,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,IAAI,CAAC;YAC9C,KAAK,EAAE,QAAQ,CAAC,KAAc;SAC/B,CAAC;QACF,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;QAE9C,QAAQ,QAAQ,CAAC,KAAK,EAAE,CAAC;YACvB,KAAK,iBAAK,CAAC,SAAS;gBAClB,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;gBAClD,MAAM;YACR,KAAK,iBAAK,CAAC,SAAS;gBAClB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;gBACvD,MAAM;YACR;gBACE,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;IAED;;OAEG;IACH,gBAAgB,CAAI,KAAwB,EAAE,QAAW;QACvD,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IACnD,CAAC;IAED;;OAEG;IACH,OAAO,CAAI,KAAwB;QACjC,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACvC,CAAC;IAED;;OAEG;IACH,YAAY,CAAI,KAAwB;QACtC,OAAO,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,SAAS,CAAC,cAAc,EAAE,CAAC;IAClC,CAAC;IAED;;OAEG;IACH,WAAW;QACT,MAAM,KAAK,GAAG,IAAI,SAAS,EAAE,CAAC;QAC9B,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,oBAAoB,EAAE,CAAC;QACxD,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACH,YAAY;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED;;OAEG;IACH,mBAAmB;QACjB,OAAO,IAAI,CAAC,gBAAgB,CAAC;IAC/B,CAAC;IAED;;OAEG;IACH,cAAc,CAAC,IAA0C;QACvD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IACvF,CAAC;IAED;;OAEG;IACH,iBAAiB;QACf,OAAO,IAAI,CAAC,cAAc,CAAC,YAAY,CAA8B,CAAC;IACxE,CAAC;IAED;;OAEG;IACK,eAAe,CAAC,QAAa,EAAE,IAA0C;QAC/E,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,YAAY;gBACf,OAAO,OAAO,CAAC,WAAW,CAAC,yBAAa,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;YACjE,KAAK,QAAQ;gBACX,OAAO,OAAO,CAAC,WAAW,CAAC,yBAAa,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YAC7D,KAAK,UAAU;gBACb,OAAO,OAAO,CAAC,WAAW,CAAC,yBAAa,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;YACjE;gBACE,OAAO,IAAI,CAAC;QAChB,CAAC;IACH,CAAC;CACF;AAhID,8BAgIC"} |
@@ -1,3 +0,4 @@ | ||
| export * from './container'; | ||
| export * from './injection-token'; | ||
| export * from "./container"; | ||
| export * from "./injection-token"; | ||
| export type { LogicalContainerItem, ControllerContainerItem } from "./container"; | ||
| //# sourceMappingURL=index.d.ts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/container/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC"} | ||
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/container/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,YAAY,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC"} |
+1
-1
| { | ||
| "name": "@hestjs/core", | ||
| "version": "0.1.8", | ||
| "version": "0.1.9", | ||
| "description": "HestJS Core Framework - A TypeScript framework built on Hono with dependency injection and decorators", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
+326
-262
@@ -1,373 +0,440 @@ | ||
| # HestJS 🚀 | ||
| # @hestjs/core | ||
| 一个基于 **Hono + Bun + TSyringe** 的现代化 TypeScript 后端框架,提供类似 NestJS 的开发体验,但具有更轻量和更高性能的特点。 | ||
| <div align="center"> | ||
| [](https://www.npmjs.com/package/@hestjs/core) | ||
| [](https://www.typescriptlang.org/) | ||
| [](https://bun.sh/) | ||
| [](https://hono.dev/) | ||
| [](LICENSE) | ||
| [](https://opensource.org/licenses/MIT) | ||
| ## ✨ 特性 | ||
| </div> | ||
| - 🎯 **装饰器驱动** - 使用装饰器定义控制器、服务、中间件 | ||
| - 💉 **依赖注入** - 基于 TSyringe 的完整 DI 容器,用户透明 | ||
| - 🏗️ **模块化架构** - 采用模块系统组织代码 | ||
| - ⚡ **高性能** - 基于 Hono 和 Bun 获得最佳性能 | ||
| - 🔒 **类型安全** - 完全的 TypeScript 支持 | ||
| - 🛡️ **验证系统** - 基于 TypeBox 的强大验证功能 | ||
| - 🔄 **拦截器** - 灵活的请求/响应拦截机制 | ||
| - 🚨 **异常处理** - 完善的异常过滤和处理系统 | ||
| HestJS 核心包 - 基于 Hono 构建的现代化 TypeScript 后端库,提供装饰器驱动的开发体验和依赖注入系统。 | ||
| ## 🚀 快速开始 | ||
| ## 🎯 核心理念 | ||
| ### 安装 | ||
| - **🔓 拒绝过度封装**:直接暴露原生 Hono 实例,保留所有底层功能 | ||
| - **✈️ 零配置**:你看不到类似 `hestjs.config.ts`这样的配置文件,无需任何配置 | ||
| - **🎯 装饰器驱动**:提供熟悉的 NestJS 风格开发体验 | ||
| - **💉 轻量依赖注入**:基于 TSyringe 的简洁 DI 容器 | ||
| - **⚡ 极致性能**:基于 Hono 和 Bun 的高性能运行时 | ||
| ## 📦 安装 | ||
| ```bash | ||
| # 克隆项目 | ||
| git clone https://github.com/aqz236/hest.git | ||
| cd HestJS | ||
| npm install @hestjs/core | ||
| # 或 | ||
| yarn add @hestjs/core | ||
| # 或 | ||
| bun add @hestjs/core | ||
| ``` | ||
| # 安装依赖 | ||
| bun install | ||
| ## 🚀 快速开始 | ||
| # 构建包 | ||
| bun run build | ||
| ### 1. 创建基础应用 | ||
| # 运行示例应用 | ||
| cd apps/hest-demo | ||
| bun run dev | ||
| 在此之前你应该在tsconfig中添加以下内容: | ||
| ```json | ||
| { | ||
| "compilerOptions": { | ||
| ... | ||
| "experimentalDecorators": true, | ||
| "emitDecoratorMetadata": true, | ||
| "esModuleInterop": true | ||
| } | ||
| } | ||
| ``` | ||
| ### 创建你的第一个应用 | ||
| ```typescript | ||
| // app.controller.ts | ||
| import { Controller, Get, Post, Body } from "@hestjs/core"; | ||
| import { IsString, IsEmail, IsNumber } from "@hestjs/validation"; | ||
| import { Controller, Get, HestFactory, Module } from "@hestjs/core"; | ||
| export class CreateUserDto { | ||
| @IsString({ minLength: 2, maxLength: 50 }) | ||
| name!: string; | ||
| @Controller("/") | ||
| export class WelcomeController { | ||
| @Get("/welcome") | ||
| async welcome() { | ||
| return "Welcome to HestJS!"; | ||
| } | ||
| } | ||
| @IsEmail() | ||
| email!: string; | ||
| @Module({ | ||
| controllers: [WelcomeController], | ||
| providers: [], | ||
| imports: [], | ||
| exports: [], | ||
| }) | ||
| export class AppModule {} | ||
| @IsNumber({ minimum: 0, maximum: 120 }) | ||
| age!: number; | ||
| async function bootstrap() { | ||
| const app = await HestFactory.create(AppModule); | ||
| const hono = app.hono(); | ||
| Bun.serve({ | ||
| port: 3000, | ||
| fetch: hono.fetch, | ||
| }); | ||
| } | ||
| @Controller("/api") | ||
| export class AppController { | ||
| @Get("/users") | ||
| getUsers() { | ||
| return { users: [] }; | ||
| bootstrap(); | ||
| ``` | ||
| ### 2. 定义控制器 | ||
| ```typescript | ||
| import { Controller, Get, Post, Context, Body, Param } from "@hestjs/core"; | ||
| import type { HestContext } from "@hestjs/core"; | ||
| @Controller("/users") | ||
| export class UsersController { | ||
| @Get("/") | ||
| async getAllUsers() { | ||
| return { message: "Get all users" }; | ||
| } | ||
| @Post("/users") | ||
| createUser(@Body(CreateUserDto) createUserDto: CreateUserDto) { | ||
| // createUserDto 已经过验证和类型转换 | ||
| return { success: true, data: createUserDto }; | ||
| @Get("/:id") | ||
| async getUser(@Param("id") id: string, @Context() c: HestContext) { | ||
| return { id, message: `Get user ${id}` }; | ||
| } | ||
| @Post("/") | ||
| async createUser(@Body() body: any, @Context() c: HestContext) { | ||
| return { message: "User created", data: body }; | ||
| } | ||
| } | ||
| ``` | ||
| ### 3. 创建模块 | ||
| ```typescript | ||
| // app.module.ts | ||
| import { Module } from "@hestjs/core"; | ||
| import { AppController } from "./app.controller"; | ||
| import { UsersController } from "./users.controller"; | ||
| import { UsersService } from "./users.service"; | ||
| @Module({ | ||
| controllers: [AppController], | ||
| controllers: [UsersController], | ||
| providers: [UsersService], | ||
| exports: [UsersService], | ||
| }) | ||
| export class AppModule {} | ||
| export class UsersModule {} | ||
| ``` | ||
| ### 4. 创建服务 | ||
| ```typescript | ||
| // main.ts | ||
| import { HestFactory } from "@hestjs/core"; | ||
| import { ValidationInterceptor } from "@hestjs/validation"; | ||
| import { AppModule } from "./app.module"; | ||
| import { injectable } from "@hestjs/core"; | ||
| async function bootstrap() { | ||
| const app = await HestFactory.create(AppModule); | ||
| @injectable() | ||
| export class UsersService { | ||
| findAll() { | ||
| return [ | ||
| { id: 1, name: "John" }, | ||
| { id: 2, name: "Jane" }, | ||
| ]; | ||
| } | ||
| // 启用全局验证 | ||
| app.useGlobalInterceptors(new ValidationInterceptor()); | ||
| await app.listen(3000); | ||
| console.log("🚀 Application is running on: http://localhost:3000"); | ||
| findOne(id: number) { | ||
| return { id, name: `User ${id}` }; | ||
| } | ||
| } | ||
| bootstrap(); | ||
| ``` | ||
| ## 📁 项目结构 | ||
| ## 🏗️ 架构概览 | ||
| ### 核心模块 | ||
| HestJS Core 包含以下主要模块: | ||
| ``` | ||
| packages/ | ||
| ├── core/ # 核心框架包 | ||
| │ ├── decorators/ # 装饰器定义 | ||
| │ ├── interfaces/ # 核心接口 | ||
| │ ├── application/ # 应用核心 | ||
| │ └── exceptions/ # 异常处理 | ||
| ├── validation/ # 验证模块 | ||
| │ ├── decorators/ # 验证装饰器 | ||
| │ ├── pipes/ # 验证管道 | ||
| │ └── interceptors/ # 验证拦截器 | ||
| └── ... | ||
| @hestjs/core/ | ||
| ├── application/ # 应用工厂和实例 | ||
| │ ├── HestFactory # 应用工厂 | ||
| │ └── HestApplicationInstance # 应用实例 | ||
| ├── decorators/ # 装饰器系统 | ||
| │ ├── @Controller # 控制器装饰器 | ||
| │ ├── @Module # 模块装饰器 | ||
| │ ├── @injectable # 可注入装饰器 | ||
| │ └── 路由装饰器 # @Get, @Post, @Put, @Delete, @Patch | ||
| ├── container/ # 依赖注入容器 | ||
| ├── router/ # 路由系统 | ||
| ├── exceptions/ # 异常处理 | ||
| ├── interceptors/ # 拦截器 | ||
| ├── interfaces/ # 类型定义 | ||
| └── utils/ # 工具函数 | ||
| ``` | ||
| ## 🎯 核心概念 | ||
| ## 📚 API 参考 | ||
| ### 控制器 (Controllers) | ||
| ### 🏭 应用工厂 | ||
| #### `HestFactory.create(moduleClass)` | ||
| 创建应用实例的静态方法。 | ||
| ```typescript | ||
| @Controller("/users") | ||
| export class UserController { | ||
| @Get("/") | ||
| findAll() { | ||
| return { users: [] }; | ||
| } | ||
| import { HestFactory } from "@hestjs/core"; | ||
| import { AppModule } from "./app.module"; | ||
| @Get("/:id") | ||
| findOne(@Param("id") id: string) { | ||
| return { user: { id } }; | ||
| } | ||
| const app = await HestFactory.create(AppModule); | ||
| ``` | ||
| @Post("/") | ||
| create(@Body(CreateUserDto) createUserDto: CreateUserDto) { | ||
| return { success: true }; | ||
| } | ||
| ### 🎮 控制器装饰器 | ||
| #### `@Controller(path?: string)` | ||
| 定义控制器类和基础路径。 | ||
| ```typescript | ||
| @Controller("/api/users") | ||
| export class UsersController { | ||
| // 控制器方法 | ||
| } | ||
| ``` | ||
| ### 服务和依赖注入 (Services & DI) | ||
| ### 🛣️ 路由装饰器 | ||
| #### HTTP 方法装饰器 | ||
| - `@Get(path?: string)` - GET 请求 | ||
| - `@Post(path?: string)` - POST 请求 | ||
| - `@Put(path?: string)` - PUT 请求 | ||
| - `@Delete(path?: string)` - DELETE 请求 | ||
| - `@Patch(path?: string)` - PATCH 请求 | ||
| ```typescript | ||
| @Injectable() | ||
| export class UserService { | ||
| async findAll() { | ||
| return []; | ||
| } | ||
| @Controller('/users') | ||
| export class UsersController { | ||
| @Get('/') // GET /users/ | ||
| @Get('/:id') // GET /users/:id | ||
| @Post('/') // POST /users/ | ||
| @Put('/:id') // PUT /users/:id | ||
| @Delete('/:id') // DELETE /users/:id | ||
| @Patch('/:id') // PATCH /users/:id | ||
| } | ||
| ``` | ||
| async create(userData: any) { | ||
| // 创建用户逻辑 | ||
| return userData; | ||
| } | ||
| ### 📥 参数装饰器 | ||
| #### `@Context()` | ||
| 获取完整的 Hono Context 对象。 | ||
| ```typescript | ||
| @Get('/') | ||
| async getUsers(@Context() c: HestContext) { | ||
| // 访问所有 Hono Context 功能 | ||
| const userAgent = c.req.header('User-Agent'); | ||
| return c.json({ message: 'Hello' }); | ||
| } | ||
| ``` | ||
| @Controller("/users") | ||
| export class UserController { | ||
| constructor(private readonly userService: UserService) {} | ||
| #### `@Body()` | ||
| @Get("/") | ||
| async findAll() { | ||
| return await this.userService.findAll(); | ||
| } | ||
| 获取请求体数据。 | ||
| ```typescript | ||
| @Post('/') | ||
| async createUser(@Body() userData: CreateUserDto) { | ||
| return userData; | ||
| } | ||
| ``` | ||
| ### 验证系统 (Validation) | ||
| #### `@Param(key?: string)` | ||
| #### 基础验证装饰器 | ||
| 获取路径参数。 | ||
| ```typescript | ||
| export class CreateUserDto { | ||
| @IsString({ minLength: 2, maxLength: 50 }) | ||
| name!: string; | ||
| @Get('/:id') | ||
| async getUser(@Param('id') id: string) { | ||
| return { id }; | ||
| } | ||
| ``` | ||
| @IsEmail() | ||
| email!: string; | ||
| #### `@Query(key?: string)` | ||
| @IsNumber({ minimum: 18, maximum: 100 }) | ||
| age!: number; | ||
| 获取查询参数。 | ||
| @IsOptional() | ||
| @IsString() | ||
| bio?: string; | ||
| ```typescript | ||
| @Get('/') | ||
| async getUsers(@Query('page') page: string) { | ||
| return { page }; | ||
| } | ||
| ``` | ||
| #### 自定义验证 (TypeBox API) | ||
| #### `@Header(key?: string)` | ||
| 获取请求头。 | ||
| ```typescript | ||
| import { Type } from "@sinclair/typebox"; | ||
| import { Custom, CommonValidators, SchemaFactory } from "@hestjs/validation"; | ||
| @Get('/') | ||
| async getUsers(@Header('authorization') auth: string) { | ||
| return { auth }; | ||
| } | ||
| ``` | ||
| export class AdvancedDto { | ||
| // 使用 TypeBox API 自定义验证 | ||
| @Custom( | ||
| Type.String({ | ||
| minLength: 3, | ||
| maxLength: 20, | ||
| pattern: "^[a-zA-Z0-9_]+$", | ||
| }) | ||
| ) | ||
| username!: string; | ||
| ### 🏗️ 模块系统 | ||
| // 使用联合类型 | ||
| @Custom( | ||
| Type.Union([ | ||
| Type.Literal("admin"), | ||
| Type.Literal("user"), | ||
| Type.Literal("guest"), | ||
| ]) | ||
| ) | ||
| role!: "admin" | "user" | "guest"; | ||
| #### `@Module(options)` | ||
| // 使用常用验证器 | ||
| @CommonValidators.UUID() | ||
| userId!: string; | ||
| 定义模块和依赖关系。 | ||
| // 使用便捷构建器 | ||
| @Custom(SchemaFactory.chinesePhoneNumber()) | ||
| phoneNumber!: string; | ||
| ```typescript | ||
| interface ModuleOptions { | ||
| imports?: any[]; // 导入的模块 | ||
| controllers?: any[]; // 控制器 | ||
| providers?: any[]; // 提供者(服务) | ||
| exports?: any[]; // 导出的提供者 | ||
| } | ||
| // 复杂对象验证 | ||
| @Custom( | ||
| Type.Object({ | ||
| lat: Type.Number({ minimum: -90, maximum: 90 }), | ||
| lng: Type.Number({ minimum: -180, maximum: 180 }), | ||
| }) | ||
| ) | ||
| location!: { lat: number; lng: number }; | ||
| @Module({ | ||
| imports: [DatabaseModule], | ||
| controllers: [UsersController], | ||
| providers: [UsersService], | ||
| exports: [UsersService], | ||
| }) | ||
| export class UsersModule {} | ||
| ``` | ||
| ### 💉 依赖注入 | ||
| #### `@injectable()` | ||
| 标记类为可注入的服务。 | ||
| ```typescript | ||
| @injectable() | ||
| export class UsersService { | ||
| constructor(private readonly databaseService: DatabaseService) {} | ||
| } | ||
| ``` | ||
| ### 拦截器 (Interceptors) | ||
| ### 🔄 拦截器和过滤器 | ||
| #### 全局拦截器 | ||
| ```typescript | ||
| import { Interceptor, ExecutionContext, CallHandler } from "@hestjs/core"; | ||
| const app = await HestFactory.create(AppModule); | ||
| export class LoggingInterceptor implements Interceptor { | ||
| intercept(context: ExecutionContext, next: CallHandler) { | ||
| console.log("Before..."); | ||
| // 添加全局拦截器 | ||
| app.useGlobalInterceptors(new ValidationInterceptor()); | ||
| app.useGlobalInterceptors(new ResponseInterceptor()); | ||
| ``` | ||
| const now = Date.now(); | ||
| return next.handle().then(() => { | ||
| console.log(`After... ${Date.now() - now}ms`); | ||
| }); | ||
| } | ||
| } | ||
| #### 全局异常过滤器 | ||
| // 使用拦截器 | ||
| app.useGlobalInterceptors(new LoggingInterceptor()); | ||
| ```typescript | ||
| const app = await HestFactory.create(AppModule); | ||
| // 添加全局异常过滤器 | ||
| app.useGlobalFilters(new HttpExceptionFilter()); | ||
| ``` | ||
| ### 异常处理 (Exception Handling) | ||
| ### 🌐 直接访问 Hono | ||
| HestJS 不会封装 Hono,你可以直接使用所有 Hono 功能: | ||
| ```typescript | ||
| import { | ||
| HttpException, | ||
| NotFoundException, | ||
| BadRequestException, | ||
| } from "@hestjs/core"; | ||
| const app = await HestFactory.create(AppModule); | ||
| const honoApp = app.hono(); | ||
| @Controller("/users") | ||
| export class UserController { | ||
| @Get("/:id") | ||
| findOne(@Param("id") id: string) { | ||
| const user = this.findUserById(id); | ||
| if (!user) { | ||
| throw new NotFoundException(`User with id ${id} not found`); | ||
| } | ||
| return user; | ||
| } | ||
| // 使用 Hono 原生中间件 | ||
| honoApp.use(cors()); | ||
| honoApp.use("/api/*", async (c, next) => { | ||
| console.log(`${c.req.method} ${c.req.url}`); | ||
| await next(); | ||
| }); | ||
| @Post("/") | ||
| create(@Body() userData: any) { | ||
| if (!userData.email) { | ||
| throw new BadRequestException("Email is required"); | ||
| } | ||
| return this.createUser(userData); | ||
| } | ||
| } | ||
| // 添加自定义路由 | ||
| honoApp.get("/health", (c) => c.text("OK")); | ||
| ``` | ||
| ## 🔧 开发状态 | ||
| ## 🧪 类型系统 | ||
| ### ✅ 已完成功能 | ||
| ### HestContext | ||
| - **Phase 1: 核心基础设施** ✅ | ||
| - 装饰器系统 (`@Controller`, `@Injectable`, `@Module`, 路由装饰器) | ||
| - 依赖注入容器 (基于 TSyringe) | ||
| - 应用工厂 (`HestFactory.create()`) | ||
| - 路由系统和参数注入 | ||
| 提供完整的 Hono Context 类型安全: | ||
| - **Phase 2: 中间件和异常处理** ✅ | ||
| - 异常处理系统 (HttpException, 异常过滤器) | ||
| - 拦截器系统 (Interceptor, ExecutionContext) | ||
| - 全局拦截器和异常过滤器支持 | ||
| ```typescript | ||
| import type { HestContext } from '@hestjs/core'; | ||
| - **Phase 3: 验证系统** ✅ | ||
| - 基于 TypeBox 的验证装饰器 | ||
| - @Custom() 装饰器支持完整 TypeBox API | ||
| - ValidationInterceptor 自动验证 | ||
| - SchemaFactory 和 CommonValidators | ||
| - 详细验证错误处理 | ||
| @Get('/') | ||
| async handler(@Context() c: HestContext) { | ||
| // 完整的 Hono Context API | ||
| const method = c.req.method; | ||
| const url = c.req.url; | ||
| const headers = c.req.header(); | ||
| ### 🚧 开发中 | ||
| return c.json({ method, url }); | ||
| } | ||
| ``` | ||
| - **Phase 4: 配置和日志系统** | ||
| - **Phase 5: 高级拦截器和管道** | ||
| - **Phase 6: CLI 工具** | ||
| ## 🔮 未来路线图 | ||
| ## 📊 性能 | ||
| ### v0.2.x - 增强功能 | ||
| 基于 Bun 运行时和 Hono 框架,HestJS 提供了卓越的性能: | ||
| - [ ] **中间件系统** - 完善的中间件装饰器支持 | ||
| - [ ] **管道系统** - 数据转换和验证管道 | ||
| - [ ] **守卫系统** - 路由级别的访问控制 | ||
| - [ ] **元数据增强** - 更丰富的反射元数据支持 | ||
| - 🚀 **快速启动** - 得益于 Bun 的快速启动时间 | ||
| - ⚡ **高吞吐量** - Hono 的高效路由和中间件系统 | ||
| - 💾 **低内存占用** - 轻量级架构设计 | ||
| - 🔧 **编译时优化** - TypeScript 装饰器元数据预处理 | ||
| ### v0.3.x - 性能优化 | ||
| ## 🛠️ 开发 | ||
| - [ ] **路由缓存** - 路由匹配性能优化 | ||
| - [ ] **依赖注入优化** - 容器解析性能提升 | ||
| - [ ] **热重载支持** - 开发环境下的热重载 | ||
| - [ ] **构建优化** - 更小的打包体积 | ||
| ### 构建项目 | ||
| ### v0.4.x - 生态系统 | ||
| ```bash | ||
| # 安装依赖 | ||
| bun install | ||
| - [ ] **WebSocket 支持** - 实时通信功能 | ||
| - [ ] **文件上传** - 内置文件处理能力 | ||
| - [ ] **缓存系统** - 多级缓存支持 | ||
| - [ ] **任务调度** - 定时任务和队列系统 | ||
| # 构建所有包 | ||
| bun run build | ||
| ### v0.5.x - 企业级功能 | ||
| # 运行测试 | ||
| bun run test | ||
| - [ ] **微服务支持** - 服务发现和通信 | ||
| - [ ] **配置管理** - 环境配置和动态配置 | ||
| - [ ] **健康检查** - 应用监控和诊断 | ||
| - [ ] **链路追踪** - 分布式追踪支持 | ||
| # 运行示例应用 | ||
| cd apps/hest-demo | ||
| bun run dev | ||
| ``` | ||
| ### v1.0.x - 稳定版本 | ||
| ### 测试验证功能 | ||
| - [ ] **API 稳定** - 向后兼容的 API | ||
| - [ ] **完整文档** - 全面的使用指南 | ||
| - [ ] **性能基准** - 与其他框架的对比 | ||
| - [ ] **生产就绪** - 企业级部署支持 | ||
| ```bash | ||
| # 运行 Phase 3 验证测试 | ||
| bun test-phase3.ts | ||
| ``` | ||
| ## 📋 当前功能状态 | ||
| ## 📖 API 参考 | ||
| ### ✅ 已实现功能 | ||
| ### 装饰器 | ||
| - [x] **应用工厂** - `HestFactory.create()` | ||
| - [x] **控制器系统** - `@Controller()` 装饰器 | ||
| - [x] **路由装饰器** - `@Get()`, `@Post()`, `@Put()`, `@Delete()`, `@Patch()` | ||
| - [x] **参数装饰器** - `@Context()`, `@Body()`, `@Param()`, `@Query()`, `@Header()` | ||
| - [x] **模块系统** - `@Module()` 装饰器 | ||
| - [x] **依赖注入** - 基于 TSyringe 的 DI 容器 | ||
| - [x] **异常处理** - 基础异常过滤器 | ||
| - [x] **拦截器** - 全局拦截器支持 | ||
| - [x] **类型安全** - 完整的 TypeScript 支持 | ||
| - [x] **Hono 集成** - 直接访问 Hono 实例 | ||
| - `@Controller(path?)` - 定义控制器 | ||
| - `@Injectable()` - 标记可注入服务 | ||
| - `@Module(options)` - 定义模块 | ||
| - `@Get(path?)`, `@Post(path?)`, `@Put(path?)`, `@Delete(path?)` - HTTP 路由 | ||
| - `@Body(dtoClass?)`, `@Param(key?)`, `@Query(key?)` - 参数注入 | ||
| - `@IsString()`, `@IsEmail()`, `@IsNumber()` - 基础验证 | ||
| - `@Custom(schema, options?)` - 自定义 TypeBox 验证 | ||
| ### 🚧 开发中功能 | ||
| ### 核心类 | ||
| - [ ] **装饰器中间件** - `@UseMiddleware()` 装饰器 | ||
| - [ ] **路由守卫** - `@UseGuards()` 装饰器 | ||
| - [ ] **数据管道** - `@UsePipes()` 装饰器 | ||
| - [ ] **OpenAPI 集成** - 自动 API 文档生成 | ||
| - `HestFactory` - 应用工厂 | ||
| - `HttpException` - HTTP 异常基类 | ||
| - `ValidationInterceptor` - 验证拦截器 | ||
| - `Interceptor` - 拦截器接口 | ||
| - `ExecutionContext` - 执行上下文 | ||
| ## 💡 设计原则 | ||
| 1. **最小封装** - 不隐藏底层框架的功能 | ||
| 2. **类型安全** - 完整的 TypeScript 支持 | ||
| 3. **性能优先** - 基于高性能的 Hono 和 Bun | ||
| 4. **开发体验** - 熟悉的装饰器语法 | ||
| 5. **渐进式** - 可以逐步采用各种功能 | ||
| ## 🤝 贡献 | ||
| 欢迎贡献代码!请查看 [贡献指南](CONTRIBUTING.md) 了解详情。 | ||
| 欢迎提交 Issue 和 Pull Request! | ||
@@ -378,11 +445,8 @@ ## 📄 许可证 | ||
| ## 🔗 相关链接 | ||
| --- | ||
| - [Hono](https://hono.dev/) - 快速、轻量级的 Web 框架 | ||
| - [Bun](https://bun.sh/) - 快速的 JavaScript 运行时 | ||
| - [TSyringe](https://github.com/microsoft/tsyringe) - 依赖注入容器 | ||
| - [TypeBox](https://github.com/sinclairzx81/typebox) - JSON Schema 类型构建器 | ||
| **更多信息**: | ||
| --- | ||
| ⭐ 如果这个项目对你有帮助,请给个 Star! | ||
| - 📚 [完整文档](https://aqz236.github.io/hestjs-demo) | ||
| - 🎮 [示例项目](https://github.com/aqz236/hestjs-demo) | ||
| - 🐛 [问题反馈](https://github.com/aqz236/hest/issues) |
157950
6.65%138
2.99%2551
6.83%452
16.49%