📦 @notjustcoders/ioc-arise
CLI tool for analyzing code and generating containers. AST-powered analysis detects dependencies automatically.
IoC-Arise is a complete dependency injection solution for TypeScript:
📦 @notjustcoders/ioc-arise
CLI tool for analyzing code and generating containers. AST-powered analysis detects dependencies automatically.
⚡ @notjustcoders/di-container
Lightweight runtime DI container (~4KB, zero decorators). Use standalone or with generated code.
# Install CLI globally or as dev dependencynpm install -D @notjustcoders/ioc-arise
# The CLI will automatically add @notjustcoders/di-container as a dependency# If you want to install both explicitlynpm install -D @notjustcoders/ioc-arisenpm install @notjustcoders/di-container# If you only want the DI container (manual setup)npm install @notjustcoders/di-containerInstall the CLI
npm install -D @notjustcoders/ioc-ariseCreate Your Services
export interface IUserService { getUser(id: string): Promise<User>;}
// services/UserService.tsexport class UserService implements IUserService { async getUser(id: string): Promise<User> { // Implementation }}Generate Container
npx @notjustcoders/ioc-arise generateUse the Container
import { container } from "./container.gen";
const userService = container.resolve('IUserService');const user = await userService.getUser('123');The basic dependency injection pattern uses interfaces and their implementations:
classDiagram
class IUserService {
<<interface>>
+getUser(id: string) Promise~User~
}
class UserService {
+getUser(id: string) Promise~User~
}
IUserService <|.. UserService : implements
Key Points:
IUserService defines the contract (interface)UserService implements the interfaceIUserService to UserService automaticallycontainer.gen.ts - Ready-to-use container instance
import { Container } from '@notjustcoders/di-container';import type { ContainerRegistry } from './container.gen.d';import { userModule } from './modules/userModule.module';
export const container = new Container<ContainerRegistry>();
container.registerModule(userModule);Benefits: ✅ All imports auto-generated • ✅ Modules automatically registered • ✅ Type-safe with ContainerRegistry • ✅ Full IntelliSense support
container.gen.d.ts - Full IntelliSense support
import type { IUserService } from './services/IUserService';
export interface ContainerRegistry { 'IUserService': IUserService; // ... all your interfaces mapped}Usage with type safety:
import { container } from './container.gen';
const service = container.resolve('IUserService');// ^? IUserService - Full type safety!Benefits: ✅ Autocomplete for all tokens • ✅ Compile-time type checking • ✅ IDE refactoring support • ✅ Type-safe resolution
modules/userModule.module.ts - Organized registrations
import { ContainerModule, Lifecycle } from '@notjustcoders/di-container';import { UserService } from '../services/UserService';
export const userModule = new ContainerModule() .register('IUserService', { useClass: UserService, dependencies: ['IUserRepository'], lifecycle: Lifecycle.Singleton });Benefits: ✅ Dependencies auto-detected • ✅ Lifecycle scopes respected • ✅ Clean module separation
import { Container, Lifecycle } from '@notjustcoders/di-container';
// Define registry for type safetyinterface ContainerRegistry { 'IUserService': IUserService; 'IUserRepository': IUserRepository;}
const container = new Container<ContainerRegistry>();
// Manual registration (no code generation)container.register('IUserService', { useClass: UserService, dependencies: ['IUserRepository'], lifecycle: Lifecycle.Singleton});
// Full type safetyconst service = container.resolve('IUserService');// ^? IUserServiceWhen to use manual setup:
When to use CLI (recommended):
See the @notjustcoders/di-container documentation for more details.
Organize your code into logical modules using ioc.config.json:
{ "sourceDir": "./src", "outputPath": "./src/container.gen.ts", "interface": "I*.ts", "modules": { "UserModule": ["user/**"], "TodoModule": ["todo/**"] }}This will generate separate module files:
src/├── container.gen.ts # Main container├── container.gen.d.ts # Type declarations└── modules/ ├── userModule.module.ts # User module registrations └── todoModule.module.ts # Todo module registrationsAccess services using string tokens:
const userService = container.resolve('IUserService');const todoService = container.resolve('ITodoService');One shared instance across the entire application:
/** * @scope singleton */export class UserRepository implements IUserRepository { // ✅ Same instance reused everywhere // ✅ Good for: Databases, configs, caches // ✅ Better performance (one instantiation)}Use Cases: Database connections • Configuration services • Caching layers • Stateful services
New instance created every time:
/** * @scope transient */export class RequestLogger implements ILogger { // ✅ New instance per resolve // ✅ Good for: Request handlers, loggers // ✅ Isolated state per call}Use Cases: HTTP request handlers • Command processors • Per-request loggers • Stateless operations
Defaults to Singleton if no annotation:
export class UserService implements IUserService { // Automatically treated as singleton // Same as adding @scope singleton}Best Practice:
Always be explicit with @scope annotations for clarity!
Create an ioc.config.json file in your project root:
{ "sourceDir": "./src", // Source directory to analyze "outputPath": "./src/container.gen.ts", // Output file path "interface": "I*.ts", // Interface file pattern "exclude": [ // Files to exclude "node_modules", "dist", "**/*.test.ts" ], "modules": { // Optional module grouping "CoreModule": ["core/**"], "UserModule": ["user/**"], "TodoModule": ["todo/**"] }}📚 Examples
Explore real-world examples including Clean Architecture, modules, and use cases.
🎯 Core Features
Learn about abstract classes, scopes, and modules.
⚠️ Error Detection
Understand how IoC Arise catches circular dependencies and other issues.
📖 Reference
Check the CLI Reference and Configuration for complete documentation.