or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

array-operations.mdasync-promise-utilities.mddata-utilities.mdfunction-utilities.mdindex.mdobject-operations.mdpath-operations.mdperformance-benchmarking.mdstring-utilities.mdvalidation-assertions.md
tile.json

function-utilities.mddocs/

Function Utilities

Function wrapper utilities for controlling execution patterns and providing no-op functionality in various programming contexts.

Capabilities

Once

Wraps a function to ensure it can only execute once. The wrapped function does not return the result of the original function and subsequent calls do nothing.

/**
 * Wraps a function to ensure it can only execute once
 * @param method - The function to be wrapped
 * @returns A wrapped function that executes the method once and returns undefined on all calls
 */
function once<T extends Function>(method: T): (...args: any[]) => void;

Usage Examples:

import { once } from "@hapi/hoek";

// Basic usage
const myFunction = () => {
  console.log('This will only run once');
  return 'result';
};

const onceFunction = once(myFunction);
const result1 = onceFunction(); // Logs message, returns undefined
const result2 = onceFunction(); // Returns undefined, no log
const result3 = onceFunction(); // Returns undefined, no log

// Initialization function
const initializeApp = once(() => {
  console.log('Initializing application...');
  // Setup code here
  return { initialized: true };
});

// Safe to call multiple times
initializeApp(); // Runs initialization, returns undefined
initializeApp(); // Does nothing, returns undefined
initializeApp(); // Does nothing, returns undefined

// Event handler that should only run once
const handleFirstClick = once((event: Event) => {
  console.log('First click detected!');
  // Setup one-time behavior
});

button.addEventListener('click', handleFirstClick);
// First click triggers the handler, subsequent clicks do nothing

// Async function wrapping
const fetchUserOnce = once(async (userId: string) => {
  console.log(`Fetching user ${userId}...`);
  const response = await fetch(`/api/users/${userId}`);
  return response.json();
});

// Multiple calls, but only first one executes
const user1 = await fetchUserOnce('123'); // Fetches user, returns undefined
const user2 = await fetchUserOnce('123'); // Returns undefined
const user3 = await fetchUserOnce('456'); // Returns undefined (still same wrapped function)

// Constructor or factory function
const createSingleton = once(() => {
  return {
    id: Math.random(),
    createdAt: new Date(),
    // singleton properties
  };
});

const singleton1 = createSingleton(); // Creates instance, returns undefined
const singleton2 = createSingleton(); // Returns undefined
// Note: The created instance is not returned, you need a different pattern for singletons

// Method wrapping with context preservation
class Logger {
  private setupDone = false;
  
  constructor() {
    this.setup = once(this.setup.bind(this));
  }
  
  setup() {
    console.log('Setting up logger...');
    this.setupDone = true;
  }
  
  log(message: string) {
    this.setup(); // Safe to call multiple times
    if (this.setupDone) {
      console.log(message);
    }
  }
}

// Cleanup or teardown functions
const cleanup = once(() => {
  console.log('Cleaning up resources...');
  // Cleanup code that should only run once
});

process.on('exit', cleanup);
process.on('SIGINT', cleanup);
process.on('SIGTERM', cleanup);
// Cleanup will only run once regardless of which signal is received

Ignore

A reusable no-op function that accepts any arguments and returns undefined.

/**
 * A reusable no-op function
 * @param args - Any number of arguments (all ignored)
 * @returns undefined
 */
function ignore(...args: any): void;

Usage Examples:

import { ignore } from "@hapi/hoek";

// Default callback parameter
function processData(data: any[], callback = ignore) {
  // Process data
  for (const item of data) {
    // Do processing
  }
  callback(null, data); // Safe to call even if no callback provided
}

// Usage without callback
processData([1, 2, 3]); // Works fine, ignore handles the callback

// Promise.catch() placeholder
Promise.resolve('success')
  .then(result => console.log(result))
  .catch(ignore); // Silently ignore errors

// Event handler placeholder
const button = document.getElementById('myButton');
button?.addEventListener('click', ignore); // No-op click handler

// Optional error handling
function riskyOperation(onError = ignore) {
  try {
    // Some risky operation
    throw new Error('Something went wrong');
  } catch (error) {
    onError(error); // Safe to call even if onError is not provided
  }
}

// Array methods with placeholder functions
const data = [1, 2, 3, 4, 5];

// Placeholder for unused array callback parameters
const processedData = data.map((value, index, array) => {
  ignore(index, array); // Explicitly ignore unused parameters
  return value * 2;
});

// Stream or event emitter placeholder
const stream = new EventEmitter();
stream.on('data', ignore); // Ignore data events
stream.on('error', ignore); // Ignore error events

// Testing or development placeholder
const api = {
  development: {
    log: console.log,
    error: console.error
  },
  production: {
    log: ignore, // Disable logging in production
    error: console.error
  }
};

const logger = process.env.NODE_ENV === 'production' 
  ? api.production 
  : api.development;

logger.log('This may or may not appear');

// Conditional function execution
const debugMode = false;
const debugLog = debugMode ? console.log : ignore;

debugLog('Debug message'); // Only logs if debugMode is true

// Placeholder in function composition
const pipeline = [
  processStep1,
  processStep2,
  debugMode ? logStep : ignore,
  processStep3
];

// Clean way to handle optional operations
function setupApplication(onProgress = ignore, onComplete = ignore) {
  onProgress('Starting setup...');
  // Setup steps
  onProgress('Installing dependencies...');
  // More setup
  onComplete('Setup completed');
}

// Can call with or without callbacks
setupApplication(); // Works fine
setupApplication(console.log); // With progress logging
setupApplication(console.log, () => console.log('Done!')); // With both callbacks

Important Notes:

  • once does NOT preserve the original function's return type - all calls return undefined
  • The wrapped function executes the original function once but does not return its result
  • once is thread-safe and handles concurrent calls correctly
  • ignore is a constant function reference, making it efficient for repeated use
  • Both utilities are commonly used in callback patterns and optional parameter scenarios
  • Perfect for cleanup functions, initialization routines, and placeholder callbacks