Skip to main content

Context

The Context class is the core of the Contexify framework. It serves as a registry for bindings and provides methods for managing dependencies.

Constructor

constructor

Creates a new Context instance.

Signature:

constructor(parent?: Context, name?: string)

Parameters:

  • parent (optional): A parent Context. If provided, this Context will inherit bindings from the parent.
  • name (optional): A name for this Context. Useful for debugging.

Returns: A new Context instance.

Example:

// Create a root context
const rootContext = new Context('root');

// Create a child context
const childContext = new Context(rootContext, 'child');

Binding Methods

bind

Creates a new Binding with the given key and adds it to the Context.

Signature:

bind(key: string): Binding

Parameters:

  • key: The binding key. This is a string that uniquely identifies the binding within the Context.

Returns: A new Binding instance.

Example:

// Create a binding for a simple value
const binding = context.bind('greeting');
binding.to('Hello, world!');

// Create a binding for a class
context.bind('services.UserService').toClass(UserService);

add

Adds an existing Binding to the Context.

Signature:

add(binding: Binding): this

Parameters:

  • binding: The Binding to add.

Returns: The Context instance (for method chaining).

Example:

// Create a binding
const binding = Binding.create('greeting');
binding.to('Hello, world!');

// Add the binding to the context
context.add(binding);

unbind

Removes a Binding from the Context.

Signature:

unbind(key: string): boolean

Parameters:

  • key: The binding key to remove.

Returns: true if the binding was found and removed, false otherwise.

Example:

// Remove a binding
const wasRemoved = context.unbind('greeting');
console.log(wasRemoved); // true or false

contains

Checks if the Context contains a Binding with the given key.

Signature:

contains(key: string): boolean

Parameters:

  • key: The binding key to check.

Returns: true if the binding exists, false otherwise.

Example:

// Check if a binding exists
const exists = context.contains('greeting');
console.log(exists); // true or false

Resolution Methods

get

Resolves a value from the Context asynchronously.

Signature:

get<T>(key: string, options?: ResolutionOptions): Promise<T>

Parameters:

  • key: The binding key to resolve.
  • options (optional): Options for the resolution process.

Returns: A Promise that resolves to the value.

Example:

// Resolve a value asynchronously
const greeting = await context.get<string>('greeting');
console.log(greeting); // Hello, world!

// Resolve a service
const userService = await context.get<UserService>('services.UserService');

getSync

Resolves a value from the Context synchronously.

Signature:

getSync<T>(key: string, options?: ResolutionOptions): T

Parameters:

  • key: The binding key to resolve.
  • options (optional): Options for the resolution process.

Returns: The resolved value.

Throws: If the value cannot be resolved synchronously (e.g., if it involves async operations).

Example:

// Resolve a value synchronously
const greeting = context.getSync<string>('greeting');
console.log(greeting); // Hello, world!

getBinding

Gets a Binding from the Context.

Signature:

getBinding(key: string): Binding | undefined

Parameters:

  • key: The binding key to get.

Returns: The Binding if found, undefined otherwise.

Example:

// Get a binding
const binding = context.getBinding('greeting');
if (binding) {
console.log('Binding found!');
}

find

Finds all Bindings that match the given pattern.

Signature:

find(pattern: string | RegExp): Promise<Binding[]>

Parameters:

  • pattern: A string or RegExp pattern to match against binding keys.

Returns: A Promise that resolves to an array of matching Bindings.

Example:

// Find all bindings that match a pattern
const serviceBindings = await context.find(/^services\./);
console.log(`Found ${serviceBindings.length} service bindings`);

findByTag

Finds all Bindings that have the given tag.

Signature:

findByTag(tag: string): Promise<Binding[]>

Parameters:

  • tag: The tag to search for.

Returns: A Promise that resolves to an array of matching Bindings.

Example:

// Find all bindings with a specific tag
const serviceBindings = await context.findByTag('service');
console.log(`Found ${serviceBindings.length} service bindings`);

Configuration Methods

configure

Creates a configuration binding for the given key.

Signature:

configure(key: string): Binding

Parameters:

  • key: The binding key to configure.

Returns: A new Binding instance for the configuration.

Example:

// Configure a service
context.configure('services.EmailService').to({
host: 'smtp.example.com',
port: 587,
secure: true,
});

getConfig

Gets the configuration for a binding.

Signature:

getConfig<T>(key: string, options?: ResolutionOptions): Promise<T>

Parameters:

  • key: The binding key to get the configuration for.
  • options (optional): Options for the resolution process.

Returns: A Promise that resolves to the configuration value.

Example:

// Get configuration for a service
const emailConfig = await context.getConfig<EmailConfig>('services.EmailService');
console.log(emailConfig.host); // smtp.example.com

Context View Methods

createView

Creates a ContextView that tracks bindings matching the given filter.

Signature:

createView<T>(filter: BindingFilter, comparator?: BindingComparator): ContextView<T>

Parameters:

  • filter: A function that filters bindings.
  • comparator (optional): A function that compares bindings for sorting.

Returns: A new ContextView instance.

Example:

// Create a view of all service bindings
const serviceView = context.createView<any>(
binding => binding.tags.has('service'),
(a, b) => a.key.localeCompare(b.key)
);

// Get all services
const services = await serviceView.resolve();

Observer Methods

subscribe

Subscribes an observer to context events.

Signature:

subscribe(observer: ContextEventObserver): this

Parameters:

  • observer: The observer to subscribe.

Returns: The Context instance (for method chaining).

Example:

// Create an observer
class ServiceObserver implements ContextObserver {
filter = binding => binding.tags.has('service');

observe(event: string, binding: Binding) {
console.log(`Service event: ${event}, binding: ${binding.key}`);
}
}

// Subscribe the observer
context.subscribe(new ServiceObserver());

unsubscribe

Unsubscribes an observer from context events.

Signature:

unsubscribe(observer: ContextEventObserver): boolean

Parameters:

  • observer: The observer to unsubscribe.

Returns: true if the observer was found and removed, false otherwise.

Example:

// Create an observer
const observer = new ServiceObserver();

// Subscribe the observer
context.subscribe(observer);

// Later, unsubscribe the observer
const wasRemoved = context.unsubscribe(observer);
console.log(wasRemoved); // true or false

Event Methods

on

Adds an event listener for the given event.

Signature:

on(event: string, listener: ContextEventListener): this

Parameters:

  • event: The event name.
  • listener: The event listener function.

Returns: The Context instance (for method chaining).

Example:

// Listen for bind events
context.on('bind', (binding, context) => {
console.log(`Binding added: ${binding.key}`);
});

once

Adds a one-time event listener for the given event.

Signature:

once(event: string, listener: ContextEventListener): this

Parameters:

  • event: The event name.
  • listener: The event listener function.

Returns: The Context instance (for method chaining).

Example:

// Listen for the next bind event only
context.once('bind', (binding, context) => {
console.log(`Binding added: ${binding.key}`);
});

off

Removes an event listener for the given event.

Signature:

off(event: string, listener: ContextEventListener): this

Parameters:

  • event: The event name.
  • listener: The event listener function to remove.

Returns: The Context instance (for method chaining).

Example:

// Create a listener
const listener = (binding, context) => {
console.log(`Binding added: ${binding.key}`);
};

// Add the listener
context.on('bind', listener);

// Later, remove the listener
context.off('bind', listener);

Lifecycle Methods

close

Closes the Context, releasing all resources and removing all bindings.

Signature:

close(): void

Example:

// Close the context when done
context.close();

Events

The Context class emits the following events:

  • bind: Emitted when a binding is added to the context.
  • unbind: Emitted when a binding is removed from the context.
  • resolve:before: Emitted before a binding is resolved.
  • resolve:after: Emitted after a binding is resolved.
  • error: Emitted when an error occurs during resolution.

Complete Example

Here's a complete example showing how to use the Context class:

import { Context, injectable, inject } from 'contexify';

// Create a context
const context = new Context('application');

// Define a logger service
@injectable()
class LoggerService {
log(message: string) {
console.log(`[LOG] ${message}`);
}
}

// Define a user service that depends on the logger
@injectable()
class UserService {
constructor(@inject('services.LoggerService') private logger: LoggerService) {}

createUser(name: string) {
this.logger.log(`Creating user: ${name}`);
return { id: Date.now().toString(), name };
}
}

// Bind the services to the context
context.bind('services.LoggerService').toClass(LoggerService);
context.bind('services.UserService').toClass(UserService);

// Subscribe to events
context.on('bind', (binding) => {
console.log(`Binding added: ${binding.key}`);
});

// Use the services
async function run() {
// Resolve the UserService from the context
const userService = await context.get<UserService>('services.UserService');

// Create a user
const user = userService.createUser('John');
console.log('Created user:', user);

// Close the context when done
context.close();
}

run().catch(err => console.error(err));