or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-delegates

Node method and accessor delegation utility for creating clean object composition patterns

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/delegates@1.0.x

To install, run

npx @tessl/cli install tessl/npm-delegates@1.0.0

index.mddocs/

Delegates

Delegates is a Node.js utility for creating delegation patterns in JavaScript. It allows methods and property accessors to be delegated from one object to a property of that object, providing a fluent API for setting up clean object composition without manually writing wrapper functions.

Package Information

  • Package Name: delegates
  • Package Type: npm
  • Language: JavaScript
  • Installation: npm install delegates

Core Imports

const delegate = require('delegates');

Basic Usage

const delegate = require('delegates');

// Create a simple object with a target property
const obj = {
  request: {
    method: 'GET',
    url: '/api/users',
    headers: { 'Content-Type': 'application/json' }
  }
};

// Set up delegation from obj to obj.request
delegate(obj, 'request')
  .method('send')           // Delegate method calls
  .access('method')         // Delegate getter and setter
  .getter('headers')        // Delegate getter only
  .setter('timeout')        // Delegate setter only
  .fluent('url');          // Delegate fluent accessor

// Now you can use delegated methods and properties directly on obj
obj.method = 'POST';        // Sets obj.request.method
console.log(obj.method);    // Gets obj.request.method
obj.url('/api/posts');      // Sets obj.request.url and returns obj for chaining

Architecture

Delegates uses the delegation pattern to avoid writing repetitive proxy methods. Instead of manually creating getter/setter functions, it dynamically defines properties and methods on a host object that forward to a target property.

Key components:

  • Delegator: Main class that configures delegation rules
  • Target Property: The object property that receives delegated calls
  • Host Object: The object that gains the delegated functionality
  • Delegation Types: Method calls, property access (getter/setter), and fluent accessors

The library supports both constructor-style (new Delegator()) and factory-style (delegate()) instantiation, with all configuration methods returning the delegator instance for method chaining.

Capabilities

Constructor

Creates a delegator instance for configuring method and property delegation.

/**
 * Creates a delegator instance used to configure delegation
 * @param {Object} proto - The object to add delegated methods/properties to
 * @param {string} target - The property name that methods/properties will be delegated to
 * @returns {Delegator} Delegator instance for chaining configuration calls
 */
function delegate(proto, target);

The constructor can be called with or without new:

  • delegate(proto, target)
  • new delegate(proto, target)

Method Delegation

Delegates method calls from the host object to the target property.

/**
 * Delegate method calls to the target object
 * @param {string} name - The method name to delegate
 * @returns {Delegator} Self for method chaining
 */
method(name);

Usage Example:

const obj = {
  request: {
    send: function() { return 'sent'; },
    abort: function() { return 'aborted'; }
  }
};

delegate(obj, 'request')
  .method('send')
  .method('abort');

// Now obj.send() calls obj.request.send()
obj.send();  // Returns 'sent'
obj.abort(); // Returns 'aborted'

Property Access Delegation

Creates both getter and setter for a property (full accessor).

/**
 * Create both getter and setter for a property
 * @param {string} name - The property name to create accessor for
 * @returns {Delegator} Self for method chaining
 */
access(name);

Usage Example:

const obj = {
  config: {
    timeout: 5000,
    retries: 3
  }
};

delegate(obj, 'config')
  .access('timeout')
  .access('retries');

// Both getting and setting work
obj.timeout = 10000;        // Sets obj.config.timeout
console.log(obj.timeout);   // Gets obj.config.timeout (10000)

Getter Delegation

Creates a getter property that delegates to the target object.

/**
 * Create a getter property that delegates to the target object
 * @param {string} name - The property name to create getter for
 * @returns {Delegator} Self for method chaining
 */
getter(name);

Usage Example:

const obj = {
  response: {
    get status() { return 200; },
    get headers() { return { 'content-type': 'application/json' }; }
  }
};

delegate(obj, 'response')
  .getter('status')
  .getter('headers');

// Read-only access to response properties
console.log(obj.status);   // 200
console.log(obj.headers);  // { 'content-type': 'application/json' }

Setter Delegation

Creates a setter property that delegates to the target object.

/**
 * Create a setter property that delegates to the target object
 * @param {string} name - The property name to create setter for
 * @returns {Delegator} Self for method chaining
 */
setter(name);

Usage Example:

const obj = {
  config: {
    _timeout: 5000,
    set timeout(value) { this._timeout = value; }
  }
};

delegate(obj, 'config')
  .setter('timeout');

// Write-only access to config property
obj.timeout = 10000;  // Sets obj.config.timeout

Fluent Accessor Delegation

Creates a fluent accessor that works as both getter and chainable setter.

/**
 * Create a fluent accessor that works as both getter and chainable setter
 * @param {string} name - The property name to create fluent accessor for
 * @returns {Delegator} Self for method chaining
 */
fluent(name);

Usage Example:

const obj = {
  request: {
    method: 'GET',
    url: '/'
  }
};

delegate(obj, 'request')
  .fluent('method')
  .fluent('url');

// Getter usage (no arguments)
console.log(obj.method());  // 'GET'
console.log(obj.url());     // '/'

// Setter usage (with argument) - returns obj for chaining
obj.method('POST').url('/api/users');
console.log(obj.request.method);  // 'POST'
console.log(obj.request.url);     // '/api/users'

Types

/**
 * Delegator constructor function
 * @constructor
 * @param {Object} proto - The object to add delegated methods/properties to
 * @param {string} target - The property name that delegation targets
 */
function Delegator(proto, target);

/**
 * Delegator instance with chainable methods
 */
interface Delegator {
  /** The object being extended with delegated functionality */
  proto: Object;
  /** The property name on proto that delegation targets */
  target: string;
  /** Array of delegated method names */
  methods: string[];
  /** Array of delegated getter names */
  getters: string[];
  /** Array of delegated setter names */
  setters: string[];
  /** Array of delegated fluent accessor names */
  fluents: string[];
  
  /** Delegate a method call */
  method(name: string): Delegator;
  /** Create both getter and setter */
  access(name: string): Delegator;
  /** Create a getter only */
  getter(name: string): Delegator;
  /** Create a setter only */
  setter(name: string): Delegator;
  /** Create a fluent accessor (getter/chainable setter) */
  fluent(name: string): Delegator;
}

Advanced Usage Patterns

Complex Delegation Setup

const delegate = require('delegates');

// HTTP request-like object
function Request(options) {
  this.options = options || {};
  this.headers = {};
}

// Delegate multiple aspects to different properties
delegate(Request.prototype, 'options')
  .access('method')
  .access('url')
  .access('timeout')
  .fluent('json');

delegate(Request.prototype, 'headers')
  .fluent('contentType')
  .fluent('authorization');

// Usage
const req = new Request({ method: 'GET', url: '/api' });
req.method = 'POST';
req.contentType('application/json')
   .authorization('Bearer token123');

Framework Integration Pattern

// Common pattern used in frameworks like Koa.js
function Context(req, res) {
  this.request = req;
  this.response = res;
}

// Delegate request properties and methods
delegate(Context.prototype, 'request')
  .method('acceptsLanguages')
  .method('acceptsCharsets')
  .access('querystring')
  .access('search')
  .getter('protocol')
  .getter('secure');

// Delegate response properties and methods  
delegate(Context.prototype, 'response')
  .method('redirect')
  .access('status')
  .access('body')
  .setter('type');