CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-insert-koin--koin-core-js

KOIN - Kotlin simple Dependency Injection Framework for JavaScript/Browser platform

Pending
Overview
Eval results
Files

dependency-injection.mddocs/

Dependency Resolution and Injection

Core dependency injection functionality for retrieving instances, lazy injection, parameter passing, and component-based dependency access.

Capabilities

Core Dependency Resolution

Get instances from the Koin container with type safety and parameter injection.

class Koin {
  /**
   * Get instance of type T from the container
   * @param qualifier - Optional qualifier for specific instance
   * @param parameters - Optional parameters for instance creation  
   * @returns Instance of type T
   * @throws NoDefinitionFoundException if definition not found
   */
  get<T>(qualifier?: Qualifier, parameters?: ParametersDefinition): T;
  get<T>(clazz: any, qualifier?: Qualifier, parameters?: ParametersDefinition): T;

  /**
   * Get instance or null if not found - safe alternative to get()
   * @param qualifier - Optional qualifier for specific instance
   * @param parameters - Optional parameters for instance creation
   * @returns Instance of type T or null if not found
   */
  getOrNull<T>(qualifier?: Qualifier, parameters?: ParametersDefinition): T | null;
  getOrNull<T>(clazz: any, qualifier?: Qualifier, parameters?: ParametersDefinition): T | null;

  /**
   * Lazy injection - resolved on first access
   * @param qualifier - Optional qualifier for specific instance
   * @param mode - Thread safety mode for lazy initialization (default: SYNCHRONIZED)
   * @param parameters - Optional parameters for instance creation
   * @returns Lazy<T> wrapper that resolves on first access
   */
  inject<T>(
    qualifier?: Qualifier,
    mode?: LazyThreadSafetyMode,
    parameters?: ParametersDefinition
  ): Lazy<T>;
  
  /**
   * Lazy injection that can return null if not found
   * @param qualifier - Optional qualifier for specific instance
   * @param mode - Thread safety mode for lazy initialization (default: SYNCHRONIZED)
   * @param parameters - Optional parameters for instance creation
   * @returns Lazy<T | null> wrapper that resolves on first access
   */
  injectOrNull<T>(
    qualifier?: Qualifier,
    mode?: LazyThreadSafetyMode,
    parameters?: ParametersDefinition
  ): Lazy<T | null>;

  /**
   * Get all instances of type T from the container
   * @returns Array of all instances matching type T
   */
  getAll<T>(): T[];

  /**
   * Declare existing instance in container for injection
   * @param instance - Instance to declare
   * @param qualifier - Optional qualifier for identification
   * @param secondaryTypes - Additional types to bind
   * @param allowOverride - Whether to allow overriding existing definition
   */
  declare<T>(
    instance: T,
    qualifier?: Qualifier,
    secondaryTypes?: any[],
    allowOverride?: boolean
  ): void;
}

Usage Examples:

import { startKoin, module } from "koin-core";

// Setup
const appModule = module((builder) => {
  builder.single(() => new DatabaseService("localhost:5432"));
  builder.factory(() => new ApiClient());
  builder.single("cache", () => new CacheService());
});

startKoin((app) => app.modules([appModule]));

// Get Koin instance
const koin = GlobalContext.get();

// Basic instance retrieval
const database = koin.get(); // DatabaseService
const apiClient = koin.get(); // ApiClient (new instance each time)

// Qualified instance retrieval
const cache = koin.get("cache"); // CacheService

// Safe retrieval
const optionalService = koin.getOrNull(); // Service | null

// With parameters
const userService = koin.get(null, () => parametersOf("user123", true));

// Get all instances of a type
const allHandlers = koin.getAll(); // MessageHandler[]

// Declare runtime instance
const runtimeService = new RuntimeService();
koin.declare(runtimeService, "runtime");

Component-Based Injection

Use the KoinComponent interface to add dependency injection capabilities to your classes.

interface KoinComponent {
  /**
   * Get the Koin container instance
   * @returns Koin container for dependency resolution
   */
  getKoin(): Koin;
}

// Extension functions for KoinComponent
/**
 * Get dependency instance from component
 * @param qualifier - Optional qualifier for specific instance
 * @param parameters - Optional parameters for instance creation
 * @returns Instance of type T
 */
function get<T>(
  this: KoinComponent,
  qualifier?: Qualifier,
  parameters?: () => ParametersHolder
): T;

/**
 * Lazy dependency injection for component
 * @param qualifier - Optional qualifier for specific instance
 * @param mode - Thread safety mode for lazy initialization
 * @param parameters - Optional parameters for instance creation
 * @returns Lazy<T> wrapper that resolves on first access
 */
function inject<T>(
  this: KoinComponent,
  qualifier?: Qualifier,
  mode?: LazyThreadSafetyMode,
  parameters?: () => ParametersHolder
): Lazy<T>;

Usage Examples:

import { KoinComponent } from "koin-core";

class UserController extends KoinComponent {
  constructor() {
    super();
    // Direct injection
    this.userService = this.get(); // UserService
    this.logger = this.get("console"); // ConsoleLogger
    
    // Lazy injection - resolved on first access
    this.cacheLazy = this.inject(); // Lazy<CacheService>
    this.apiClientLazy = this.inject("external"); // Lazy<ExternalApiClient>
  }
  
  async getUser(id) {
    // Access lazy dependencies
    const cache = this.cacheLazy.value;
    const apiClient = this.apiClientLazy.value;
    
    // Use injected dependencies
    this.logger.info(`Getting user ${id}`);
    return await this.userService.findById(id);
  }
}

// Alternative implementation using composition
class ProductService {
  constructor() {
    this.koinComponent = new KoinComponent();
    this.database = this.koinComponent.get(); // DatabaseService
    this.validator = this.koinComponent.get("product"); // ProductValidator
  }
}

Property Injection

Inject configuration properties and runtime values.

class Koin {
  /**
   * Get property value by key
   * @param key - Property key
   * @param defaultValue - Default value if property not found
   * @returns Property value of type T
   */
  getProperty<T>(key: string, defaultValue?: T): T;

  /**
   * Get property value or null if not found
   * @param key - Property key
   * @returns Property value or null
   */
  getPropertyOrNull<T>(key: string): T | null;

  /**
   * Set property value
   * @param key - Property key
   * @param value - Property value
   */
  setProperty(key: string, value: any): void;

  /**
   * Delete property by key
   * @param key - Property key
   */
  deleteProperty(key: string): void;
}

// Extension functions for KoinComponent
/**
 * Get property from component context
 * @param key - Property key
 * @param defaultValue - Default value if property not found
 * @returns Property value
 */
function getProperty<T>(
  this: KoinComponent,
  key: string,
  defaultValue?: T
): T;

Usage Examples:

import { startKoin, module, KoinComponent } from "koin-core";

// Setup with properties
startKoin((app) => {
  app.modules([appModule]);
  app.properties(new Map([
    ["database.url", "mongodb://localhost:27017"],
    ["api.timeout", 5000],
    ["debug.enabled", true]
  ]));
});

class DatabaseService extends KoinComponent {
  constructor() {
    super();
    // Inject properties with defaults
    this.url = this.getProperty("database.url", "mongodb://localhost:27017");
    this.timeout = this.getProperty("api.timeout", 3000);
    this.debugEnabled = this.getProperty("debug.enabled", false);
  }
}

// Direct property access
const koin = GlobalContext.get();
const apiUrl = koin.getProperty("api.url", "https://api.default.com");
const debugMode = koin.getPropertyOrNull("debug.mode"); // boolean | null

// Runtime property updates
koin.setProperty("cache.ttl", 300);
koin.deleteProperty("temp.flag");

Parameter-Based Injection

Pass parameters during dependency resolution for dynamic instance creation.

/**
 * Create parameters holder for injection
 * @param parameters - Parameter values in order
 * @returns ParametersHolder with indexed access
 */
function parametersOf(...parameters: any[]): ParametersHolder;

/**
 * Create indexed parameter array
 * @param parameters - Parameter values
 * @returns ParametersHolder with array-like access
 */
function parameterArrayOf(...parameters: any[]): ParametersHolder;

/**
 * Create parameter set for type-based access
 * @param parameters - Parameter values
 * @returns ParametersHolder with type-based access
 */
function parameterSetOf(...parameters: any[]): ParametersHolder;

/**
 * Create empty parameters holder
 * @returns Empty ParametersHolder
 */
function emptyParametersHolder(): ParametersHolder;

class ParametersHolder {
  /**
   * Get parameter by index and expected type
   * @param index - Parameter index
   * @param clazz - Expected parameter type
   * @returns Parameter value of type T
   */
  elementAt<T>(index: number, clazz?: new (...args: any[]) => T): T;

  /**
   * Get parameter by type (first matching type)
   * @returns Parameter value of type T
   */
  get<T>(): T;

  /**
   * Check if parameters are empty
   * @returns true if no parameters
   */
  isEmpty(): boolean;

  /**
   * Check if parameters exist
   * @returns true if parameters exist
   */
  isNotEmpty(): boolean;

  /**
   * Get parameter count
   * @returns Number of parameters
   */
  size(): number;

  /**
   * Destructuring support - get first parameter
   * @returns First parameter
   */
  component1<T>(): T;

  /**
   * Destructuring support - get second parameter
   * @returns Second parameter
   */
  component2<T>(): T;

  /**
   * Destructuring support - get third parameter
   * @returns Third parameter
   */
  component3<T>(): T;

  /**
   * Destructuring support - get fourth parameter
   * @returns Fourth parameter
   */
  component4<T>(): T;

  /**
   * Destructuring support - get fifth parameter
   * @returns Fifth parameter
   */
  component5<T>(): T;
}

Usage Examples:

import { module, parametersOf, KoinComponent } from "koin-core";

// Module with parameter-accepting definitions
const userModule = module((builder) => {
  builder.factory((scope, params) => {
    const userId = params.get(); // string
    const includeProfile = params.elementAt(1); // boolean
    return new UserService(userId, includeProfile);
  });
  
  builder.single((scope, params) => {
    const [host, port, database] = params.component1(), params.component2(), params.component3();
    return new DatabaseConnection(host, port, database);
  });
});

class UserController extends KoinComponent {
  async getUser(userId, includeProfile = false) {
    // Pass parameters during injection
    const userService = this.get(null, () => 
      parametersOf(userId, includeProfile)
    );
    
    return await userService.getUser();
  }
  
  async connectToDatabase() {
    // Multiple parameters
    const dbConnection = this.get(null, () => 
      parametersOf("localhost", 5432, "myapp")
    );
    
    return dbConnection.connect();  
  }
}

// Different parameter creation methods
const indexedParams = parametersOf("value1", 42, true);
const arrayParams = parameterArrayOf("item1", "item2", "item3");
const setParams = parameterSetOf(new Date(), "config", 100);
const emptyParams = emptyParametersHolder();

Lazy Injection

Defer dependency resolution until first access for performance optimization.

interface Lazy<T> {
  /**
   * Get the lazily resolved value - resolved on first access
   */
  value: T;
}

/**
 * Thread safety modes for lazy initialization
 */
enum LazyThreadSafetyMode {
  /** Thread-safe lazy initialization */
  SYNCHRONIZED = "SYNCHRONIZED",
  /** Not thread-safe but faster */
  NONE = "NONE",
  /** Thread-safe with publication safety */
  PUBLICATION = "PUBLICATION"
}

Usage Examples:

import { KoinComponent, LazyThreadSafetyMode } from "koin-core";

class ApplicationService extends KoinComponent {
  constructor() {
    super();
    
    // Lazy dependencies - resolved on first access
    this.expensiveService = this.inject(); // Lazy<ExpensiveService>
    this.cacheService = this.inject("redis"); // Lazy<RedisCache>
    
    // Thread-safe lazy with specific mode
    this.sharedResource = this.inject(
      "shared",
      LazyThreadSafetyMode.SYNCHRONIZED
    ); // Lazy<SharedResource>
  }
  
  async processData(data) {
    // Services are created only when first accessed
    const expensive = this.expensiveService.value; // Created here if not already
    const cache = this.cacheService.value; // Created here if not already
    
    // Subsequent access uses cached instance
    const cachedResult = this.cacheService.value.get("result");
    
    return await expensive.process(data);
  }
}

// Manual lazy injection
const koin = GlobalContext.get();
const lazyLogger = koin.inject("file"); // Lazy<FileLogger>

// Access when needed
function logMessage(message) {
  const logger = lazyLogger.value; // Created on first access
  logger.log(message);
}

Types

/** Function type for parameter definitions */
type ParametersDefinition = () => ParametersHolder;

/** Thread safety modes for lazy initialization */
enum LazyThreadSafetyMode {
  SYNCHRONIZED = "SYNCHRONIZED",
  NONE = "NONE", 
  PUBLICATION = "PUBLICATION"
}

/** Lazy wrapper interface */
interface Lazy<T> {
  value: T;
}

/** Exception thrown when definition is not found */
class NoDefinitionFoundException extends Error {
  constructor(message: string);
}

/** Exception thrown when instance creation fails */
class InstanceCreationException extends Error {
  constructor(message: string, cause?: Error);
}

/** Exception thrown when required parameter is not found */
class NoParameterFoundException extends Error {
  constructor(message: string);
}

Install with Tessl CLI

npx tessl i tessl/maven-io-insert-koin--koin-core-js

docs

application-startup.md

context-management.md

dependency-injection.md

error-handling.md

index.md

logging-system.md

module-system.md

qualifiers-parameters.md

scoping-lifecycle.md

tile.json