diff --git a/biome.json b/biome.json deleted file mode 100644 index 0a785b7..0000000 --- a/biome.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "$schema": "https://biomejs.dev/schemas/2.3.11/schema.json", - "vcs": { - "enabled": true, - "clientKind": "git", - "useIgnoreFile": true - }, - "files": { - "ignoreUnknown": false - }, - "formatter": { - "enabled": true, - "formatWithErrors": true, - "indentStyle": "tab", - "indentWidth": 4, - "lineEnding": "lf", - "lineWidth": 80, - "attributePosition": "auto" - }, - "linter": { - "enabled": true, - "rules": { - "recommended": true, - "complexity": { - "noStaticOnlyClass": "off", - "noBannedTypes": "off" - }, - "correctness": { - "noUnusedVariables": "error", - "noUnusedPrivateClassMembers": "error", - "noUnusedFunctionParameters": "off" - }, - "style": { - "useImportType": "off", - "useNodejsImportProtocol": "off", - "useTemplate": "off", - "noNonNullAssertion": "off", - "useLiteralEnumMembers": "off" - }, - "suspicious": { - "noExplicitAny": "error", - "noImplicitAnyLet": "off", - "noAssignInExpressions": "off", - "useIterableCallbackReturn": "off", - "noShadowRestrictedNames": "off" - } - } - }, - "javascript": { - "formatter": { - "quoteStyle": "double" - }, - "parser": { - "unsafeParameterDecoratorsEnabled": true - } - }, - "overrides": [ - { - "includes": ["dist/**", "node_modules/**"], - "linter": { - "enabled": false - }, - "formatter": { - "enabled": false - } - } - ] -} diff --git a/package.json b/package.json index afaa58b..45762cc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "name": "@alveojs/core", - "module": "index.ts", + "module": "src/index.ts", + "types": "src/index.ts", "type": "module", "private": true, "devDependencies": { @@ -11,6 +12,7 @@ "typescript": "^5" }, "dependencies": { + "@alveojs/common": "workspace:*", "reflect-metadata": "^0.2.2" }, "scripts": { diff --git a/src/container/Container.ts b/src/container/Container.ts index 5d6ab1e..8eb5ce8 100644 --- a/src/container/Container.ts +++ b/src/container/Container.ts @@ -1,19 +1,21 @@ import "reflect-metadata"; -import { CircularDependencyError, ProviderNotFoundError } from "../errors"; -import { ContextualModuleRef, ModuleRef } from "../module/ModuleRef"; -import type { Constructor } from "../types"; -import type { ForwardRefFn } from "./forwardRef"; import { type BaseProvider, + CircularDependencyError, + type Constructor, type DynamicModule, + type ForwardReference, INJECT_METADATA_KEY, INJECTABLE_METADATA_KEY, MODULE_METADATA_KEY, type ModuleOptions, + PARAMTYPES_METADATA_KEY, type Provider, + ProviderNotFoundError, type ProviderToken, type ResolvedProvider, -} from "./types"; +} from "@alveojs/common"; +import { ContextualModuleRef, ModuleRef } from "../module/ModuleRef"; interface ParamType { name?: string; @@ -64,13 +66,13 @@ export class Container { | Constructor | DynamicModule | Promise - | ForwardRefFn, + | ForwardReference, ): Promise { const unwrappedModule = (await (typeof module === "object" && module !== null && "forwardRef" in (module as object) ? ( - module as { forwardRef: () => Constructor | DynamicModule } + module as ForwardReference ).forwardRef() : module)) as Constructor | DynamicModule; @@ -104,9 +106,7 @@ export class Container { imp !== null && "forwardRef" in (imp as object) ? ( - imp as { - forwardRef: () => Constructor | DynamicModule; - } + imp as ForwardReference ).forwardRef() : imp); }), @@ -290,8 +290,10 @@ export class Container { } else if (provider.useClass) { const targetClass = provider.useClass; const paramTypes: ParamType[] = - Reflect.getMetadata("design:paramtypes", targetClass) || - []; + Reflect.getMetadata( + PARAMTYPES_METADATA_KEY, + targetClass, + ) || []; const injectTokens: ProviderToken[] = Reflect.getMetadata(INJECT_METADATA_KEY, targetClass) || []; diff --git a/src/container/forwardRef.ts b/src/container/forwardRef.ts deleted file mode 100644 index 039848a..0000000 --- a/src/container/forwardRef.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Interface for a function that returns a type. - */ -export type ForwardReference = () => T; - -/** - * Interface for the object returned by forwardRef. - */ -export interface ForwardRefFn { - forwardRef: ForwardReference; -} - -/** - * Allows to refer to a reference which is not yet defined. - * Useful for circular dependencies between classes or modules. - * - * @param fn A function that returns the reference - */ -export function forwardRef(fn: ForwardReference): ForwardRefFn { - return { forwardRef: fn }; -} diff --git a/src/container/types.ts b/src/container/types.ts index 532ad2d..2f601a2 100644 --- a/src/container/types.ts +++ b/src/container/types.ts @@ -1,74 +1,21 @@ -import type { Constructor, Type } from "../types"; -import type { ForwardRefFn } from "./forwardRef"; +export type { + BaseProvider, + ClassProvider, + DynamicModule, + ExistingProvider, + FactoryProvider, + InjectableOptions, + ModuleOptions, + Provider, + ProviderScope, + ProviderToken, + ResolvedProvider, + ValueProvider, +} from "@alveojs/common"; -export type ProviderScope = "singleton" | "transient"; - -export type ProviderToken = - | Type - | string - | symbol - | ForwardRefFn>; - -export interface BaseProvider { - provide: ProviderToken; - scope?: ProviderScope; -} - -export interface ClassProvider extends BaseProvider { - useClass: Constructor; -} - -export interface ValueProvider extends BaseProvider { - useValue: T; -} - -export interface FactoryProvider extends BaseProvider { - useFactory: (...args: unknown[]) => T | Promise; - inject?: ProviderToken[]; -} - -export interface ExistingProvider extends BaseProvider { - useExisting: ProviderToken; -} - -export type Provider = - | Constructor - | ClassProvider - | ValueProvider - | FactoryProvider - | ExistingProvider; - -export interface ResolvedProvider { - token: ProviderToken; - scope: ProviderScope; - useClass?: Constructor; - useValue?: T; - useFactory?: (...args: unknown[]) => T | Promise; - useExisting?: ProviderToken; - inject?: ProviderToken[]; - moduleName?: string; -} - -export interface InjectableOptions { - scope?: ProviderScope; -} - -export interface DynamicModule extends ModuleOptions { - module: Constructor; -} - -export interface ModuleOptions { - imports?: ( - | Constructor - | DynamicModule - | Promise - | ForwardRefFn - )[]; - providers?: Provider[]; - exports?: ProviderToken[]; -} - -export const INJECTABLE_METADATA_KEY = "alveo:injectable"; -export const INJECT_METADATA_KEY = "alveo:inject"; -export const MODULE_METADATA_KEY = "alveo:module"; -export const PARAMTYPES_METADATA_KEY = "design:paramtypes"; +export { + INJECT_METADATA_KEY, + INJECTABLE_METADATA_KEY, + MODULE_METADATA_KEY, + PARAMTYPES_METADATA_KEY, +} from "@alveojs/common"; diff --git a/src/decorators/index.ts b/src/decorators/index.ts deleted file mode 100644 index 88a2782..0000000 --- a/src/decorators/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./inject.decorator"; -export * from "./injectable.decorator"; -export * from "./module.decorator"; diff --git a/src/decorators/inject.decorator.ts b/src/decorators/inject.decorator.ts deleted file mode 100644 index fc82f64..0000000 --- a/src/decorators/inject.decorator.ts +++ /dev/null @@ -1,22 +0,0 @@ -import "reflect-metadata"; -import { INJECT_METADATA_KEY, type ProviderToken } from "../container/types"; - -/** - * Decorator that explicitly specifies a token for dependency injection. - * Useful when injecting interfaces (via symbols or strings) or when multiple - * providers are available for the same type. - * - * @param token The token to inject - */ -export function Inject(token: ProviderToken): ParameterDecorator { - return ( - target: object, - _propertyKey: string | symbol | undefined, - parameterIndex: number, - ) => { - const existingInjections = - Reflect.getMetadata(INJECT_METADATA_KEY, target) || []; - existingInjections[parameterIndex] = token; - Reflect.defineMetadata(INJECT_METADATA_KEY, existingInjections, target); - }; -} diff --git a/src/decorators/injectable.decorator.ts b/src/decorators/injectable.decorator.ts deleted file mode 100644 index fa2c9ad..0000000 --- a/src/decorators/injectable.decorator.ts +++ /dev/null @@ -1,16 +0,0 @@ -import "reflect-metadata"; -import { - INJECTABLE_METADATA_KEY, - type InjectableOptions, -} from "../container/types"; - -/** - * Decorator that marks a class as available to be provided and injected as a dependency. - * - * @param options Options for the injectable (e.g., scope) - */ -export function Injectable(options?: InjectableOptions): ClassDecorator { - return (target: object) => { - Reflect.defineMetadata(INJECTABLE_METADATA_KEY, options || {}, target); - }; -} diff --git a/src/decorators/module.decorator.ts b/src/decorators/module.decorator.ts deleted file mode 100644 index 7b7185d..0000000 --- a/src/decorators/module.decorator.ts +++ /dev/null @@ -1,14 +0,0 @@ -import "reflect-metadata"; -import { MODULE_METADATA_KEY, type ModuleOptions } from "../container/types"; - -/** - * Decorator that marks a class as an Alveo module. - * Modules are used to organize the application structure and define providers, imports, and exports. - * - * @param options Module configuration options - */ -export function Module(options: ModuleOptions): ClassDecorator { - return (target: object) => { - Reflect.defineMetadata(MODULE_METADATA_KEY, options, target); - }; -} diff --git a/src/errors/index.ts b/src/errors/index.ts deleted file mode 100644 index f3daeac..0000000 --- a/src/errors/index.ts +++ /dev/null @@ -1,47 +0,0 @@ -export class AlveoError extends Error { - constructor(message: string) { - super(message); - this.name = this.constructor.name; - } -} - -export class ProviderNotFoundError extends AlveoError { - constructor(token: string, context?: string) { - const contextMsg = context ? ` in the "${context}" context` : ""; - super( - `Alveo can't resolve dependencies of the ${token}${contextMsg}. Please make sure that it is available in the current module scope.`, - ); - } -} - -export class CircularDependencyError extends AlveoError { - constructor(stack: string[]) { - super(`Circular dependency detected: ${stack.join(" -> ")}`); - } -} - -export class InvalidModuleError extends AlveoError { - constructor(target: string) { - super( - `The class "${target}" is not a valid Alveo module. Did you forget the @Module() decorator?`, - ); - } -} - -export class InvalidProviderError extends AlveoError { - constructor(provider: unknown) { - super(`Invalid provider definition: ${JSON.stringify(provider)}`); - } -} - -export class LifecycleError extends AlveoError { - constructor(hook: string, error: Error) { - super(`Error during lifecycle hook "${hook}": ${error.message}`); - } -} - -export class BootstrapError extends AlveoError { - constructor(message: string) { - super(`Application bootstrap failed: ${message}`); - } -} diff --git a/src/factory/AlveoApplication.ts b/src/factory/AlveoApplication.ts index e493903..ea2fd13 100644 --- a/src/factory/AlveoApplication.ts +++ b/src/factory/AlveoApplication.ts @@ -1,5 +1,5 @@ +import type { ProviderToken } from "@alveojs/common"; import type { Container } from "../container/Container"; -import type { ProviderToken } from "../container/types"; /** * AlveoApplication is the main class representing an Alveo application instance. diff --git a/src/factory/AlveoFactory.ts b/src/factory/AlveoFactory.ts index cefab83..6b888bf 100644 --- a/src/factory/AlveoFactory.ts +++ b/src/factory/AlveoFactory.ts @@ -1,6 +1,5 @@ +import type { Constructor, DynamicModule } from "@alveojs/common"; import { Container } from "../container/Container"; -import type { DynamicModule } from "../container/types"; -import type { Constructor } from "../types"; import { AlveoApplication } from "./AlveoApplication"; /** diff --git a/src/index.ts b/src/index.ts index cbdea2f..d94fd68 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,21 +1,5 @@ +export * from "@alveojs/common"; export { Container } from "./container/Container"; -export type { ForwardReference, ForwardRefFn } from "./container/forwardRef"; -export { forwardRef } from "./container/forwardRef"; -export type { - ClassProvider, - ExistingProvider, - FactoryProvider, - InjectableOptions, - ModuleOptions, - Provider, - ProviderScope as Scope, - ProviderToken, - ValueProvider, -} from "./container/types"; -export * from "./decorators"; -export * from "./errors"; export { AlveoApplication } from "./factory/AlveoApplication"; export { AlveoFactory } from "./factory/AlveoFactory"; -export * from "./lifecycle"; export { ModuleRef } from "./module/ModuleRef"; -export type { Abstract, Constructor, Type } from "./types"; diff --git a/src/lifecycle/index.ts b/src/lifecycle/index.ts deleted file mode 100644 index 5f723f8..0000000 --- a/src/lifecycle/index.ts +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Interface defining a lifecycle hook that is called once the module has been initialized. - * All dependencies have been resolved and instantiated at this point. - */ -export interface OnModuleInit { - onModuleInit(): void | Promise; -} - -/** - * Interface defining a lifecycle hook that is called once all modules have been initialized, - * but before the application starts listening for connections. - */ -export interface OnApplicationBootstrap { - onApplicationBootstrap(): void | Promise; -} - -/** - * Interface defining a lifecycle hook that is called when the application is shutting down. - * Useful for cleanup logic like closing database connections or stopping intervals. - */ -export interface OnModuleDestroy { - onModuleDestroy(): void | Promise; -} - -/** - * Interface defining a lifecycle hook that is called after all onModuleDestroy() handlers have completed. - */ -export interface BeforeApplicationShutdown { - beforeApplicationShutdown(signal?: string): void | Promise; -} - -/** - * Interface defining a lifecycle hook that is called after connections close (app.close() resolves). - */ -export interface OnApplicationShutdown { - onApplicationShutdown(signal?: string): void | Promise; -} diff --git a/src/module/ModuleRef.ts b/src/module/ModuleRef.ts index 5c9eaf7..fcdf8b9 100644 --- a/src/module/ModuleRef.ts +++ b/src/module/ModuleRef.ts @@ -1,5 +1,5 @@ +import type { ProviderToken } from "@alveojs/common"; import type { Container } from "../container/Container"; -import type { ProviderToken } from "../container/types"; /** * ModuleRef is an abstraction that allows for dynamic resolution of providers. diff --git a/src/types.ts b/src/types.ts deleted file mode 100644 index 0cfbb73..0000000 --- a/src/types.ts +++ /dev/null @@ -1,10 +0,0 @@ -// biome-ignore lint/suspicious/noExplicitAny: Required for constructor variance compatibility -export type ConstructorArgs = any[]; - -export type Constructor = new (...args: ConstructorArgs) => T; - -export type Abstract = abstract new ( - ...args: ConstructorArgs -) => T; - -export type Type = Constructor | Abstract; diff --git a/tsconfig.json b/tsconfig.json index f63f94e..d0eadc0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,31 +1,20 @@ { + "extends": "../tsconfig.json", "compilerOptions": { - // Environment setup & latest features - "lib": ["ESNext"], - "target": "ESNext", - "module": "Preserve", - "moduleDetection": "force", "jsx": "react-jsx", "allowJs": true, "experimentalDecorators": true, "emitDecoratorMetadata": true, - - // Bundler mode - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, "verbatimModuleSyntax": true, "noEmit": true, - // Best practices - "strict": true, - "skipLibCheck": true, "noFallthroughCasesInSwitch": true, "noUncheckedIndexedAccess": true, "noImplicitOverride": true, - // Some stricter flags (disabled by default) "noUnusedLocals": false, "noUnusedParameters": false, "noPropertyAccessFromIndexSignature": false - } + }, + "include": ["src/**/*", "test/**/*", "index.ts"] }