@hapi/hoek

repository·master·Indexed 19 days ago

https://github.com/hapijs/hoek

A general purpose Node.js utility library providing specialized methods for the hapi ecosystem. It includes tools for deep cloning, merging objects, deep equality comparison, array flattening, and safe stringification, as well as utilities for escaping HTML, JSON, and Regex strings.

Tokens
10.2K
Snippets
35
Records
46
Agent score
66%

What's inside @hapi/hoek

  1. Overview of @hapi/hoek

    master

    @hapi/hoek is a collection of utility methods designed for the hapi ecosystem. While it is optimized to work seamlessly with the hapi web framework and its components, it is a standalone module that can be used with any web framework or in general-purpose Node.js applications.

    Note: If you are looking for a broad, general-purpose utility library, @lodash is recommended. @hapi/hoek is specifically curated as a central repository for methods used within the hapi ecosystem.

  2. Use @hapi/hoek utility functions

    master

    The @hapi/hoek package provides a collection of utility functions for object manipulation, string escaping, assertions, and asynchronous control. The following functions are exported as the primary public API:

    Object & Array Manipulation

    • clone(obj, [options]): Creates a clone of an object or array.
    • merge(target, source, [options]): Merges properties from a source object into a target object.
    • flatten(array): Flattens a nested array.
    • intersect(array1, array2, [options]): Returns the intersection of two arrays.
    • contain(container, value, [options]): Checks if a value exists within a container.
    • deepEqual(a, b, [options]): Performs a deep equality comparison between two values.
    • ignore(obj, [keys]): Returns a copy of an object with specified keys removed.

    String Escaping & Formatting

    • escapeHtml(str): Escapes HTML special characters.
    • escapeJson(str): Escapes a string for safe use in JSON.
    • escapeRegex(str): Escapes a string for use in a Regular Expression.
    • escapeHeaderAttribute(str): Escapes a string for use in an HTML attribute within a header.
    • stringify(obj): Converts an object to a string representation.

    Asynchronous & Control Flow

    • isPromise(value): Checks if a value is a Promise.
    • once(fn): Returns a version of a function that can only be called once.
    • wait(ms, [options]): Pauses execution for a specified number of milliseconds.
    • block(fn): Executes a function within a block (used for testing/benchmarking).
    • reach(obj, path, [options]): Retrieves a value from a nested object using a path string.
    • reachTemplate(template, data): Resolves values within a template using a data object.

    Assertions

    • assert(condition, [message]): Asserts that a condition is truthy, throwing an AssertError if not.
  3. How contain() handles different reference types

    master

    The behavior of contain(ref, values, options) depends on the type of ref:

    Strings

    Checks if the substrings in values exist within the ref string.

    • If options.only is true, the string must consist solely of the provided substrings.
    • Empty strings are handled specially: '' contains ''.

    Arrays

    Checks if the items in values are present in the ref array.

    • If options.only is true, the ref array length must match the values array length.
    • If options.once is true, each value can only be matched once.

    Objects

    • Array of keys: If values is an array, contain checks if the ref object contains all those keys.
    • Key-Value pairs: If values is an object, contain checks if ref contains the same keys with matching values.
    • Constraint: The once option cannot be used when ref is an object.
  4. Configure reach() options for Sets and Maps

    master

    By default, reach() treats Set and Map objects as standard objects and will not traverse their internal entries. To traverse them, you must enable the iterables option.

    • For Set: The path segment must be a number (or a numeric string) representing the index in the Set.
    • For Map: The path segment is used as the key for the .get() method.

    Note: If iterables is false (the default), reach() will return undefined when attempting to traverse a Set or Map via keys.

    import { reach } from '@hapi/hoek';
    
    const mySet = new Set(['apple', 'banana']);
    const myMap = new Map([['key1', 'value1']]);
    
    // Traversing a Set (requires iterables: true)
    const setVal = reach({ s: mySet }, 's.1', { iterables: true }); // 'banana'
    
    // Traversing a Map (requires iterables: true)
    const mapVal = reach({ m: myMap }, 'm.key1', { iterables: true }); // 'value1'
  5. Compare values deeply with deepEqual()

    master

    Use Hoek.deepEqual(a, b, [options]) to perform a deep comparison between two values. It supports circular dependencies, prototypes, and enumerable properties.

    Options:

    • deepFunction: (boolean) If true, function values are compared using their source code and object properties. Defaults to false.
    • part: (boolean) If true, allows a partial match where some of b is present in a. Defaults to false.
    • prototype: (boolean) If false, prototype comparisons are skipped. Defaults to true.
    • skip: (array of strings) An array of key names to skip comparing. Only applies to plain objects and deep functions. Defaults to no skipping.
    • symbols: (boolean) If false, symbol properties are ignored. Defaults to true.
    Hoek.deepEqual({ a: 1 }, { a: 1 }); // true
    Hoek.deepEqual({ a: [1, 2], b: 'string', c: { d: true } }, { a: [1, 2], b: 'string', c: { d: true } }); // true
  6. Find common items with intersect()

    master

    Use Hoek.intersect(array1, array2, [options]) to find the common unique items between two arrays.

    Options:

    • first: (boolean) If true, returns only the first intersecting item. Defaults to false.
    const array1 = [1, 2, 3];
    const array2 = [1, 4, 5];
    const newArray = Hoek.intersect(array1, array2); // results in [1]
    const array1 = [1, 2, 3];
    const array2 = [1, 4, 5];
    const newArray = Hoek.intersect(array1, array2); // results in [1]
  7. Check if a reference contains values with contain()

    master

    Use Hoek.contain(ref, values, [options]) to test if a reference value (string, array, or object) contains the provided values.

    Parameters:

    • ref: The reference string, array, or object.
    • values: A single value or an array of values to find within ref. If ref is an object, values can be a key name, an array of key names, or an object with key-value pairs.

    Options:

    • deep: (boolean) Perform a deep comparison of the values.
    • once: (boolean) Allows only one occurrence of each value.
    • only: (boolean) Does not allow values not explicitly listed.
    • part: (boolean) Allows partial match (at least one must match).
    • symbols: (boolean) Whether to include symbol properties. Defaults to true.

    Note: Comparing a string to overlapping values will fail (e.g. contain('abc', ['ab', 'bc'])). If an object key's value does not match, false is returned even if part is specified.

    Hoek.contain('aaa', 'a', { only: true }); // true
    Hoek.contain([{ a: 1 }], [{ a: 1 }], { deep: true }); // true
    Hoek.contain([1, 2, 2], [1, 2], { once: true }); // false
  8. Replace template parameters with reachTemplate()

    master

    Use Hoek.reachTemplate(obj, template, [options]) to replace string parameters in the format {name} with their corresponding values from obj using the reach() method.

    Parameters:

    • obj: The context object used for key lookup.
    • template: A string containing {} parameters.
    • options: Accepts the same options as Hoek.reach().
    const template = '1+{a.b.c}=2';
    const obj = { a: { b: { c: 1 } } };
    Hoek.reachTemplate(obj, template); // returns '1+1=2'
    const template = '1+{a.b.c}=2';
    const obj = { a: { b: { c: 1 } } };
    Hoek.reachTemplate(obj, template); // returns '1+1=2'
  9. Safe stringification with stringify()

    master

    Use Hoek.stringify(...args) to convert an object to a string using JSON.stringify(). Unlike the standard method, Hoek.stringify catches errors (like circular references) and returns them as a string instead of throwing. This is useful for logging or displaying info in error messages.

    const a = {};
    a.b = a;
    Hoek.stringify(a); // Returns '[Cannot display object: Converting circular structure to JSON]'
  10. Escape HTTP header attributes with escapeHeaderAttribute()

    master

    Use Hoek.escapeHeaderAttribute(attribute) to escape attribute values for safe use in HTTP headers.

    const a = Hoek.escapeHeaderAttribute('I said "go w\o me"'); // returns I said \"go w\o me\"
  11. Clone objects and arrays with clone()

    master

    Use Hoek.clone(obj, [options]) to create a deep copy of an object or an array. This method duplicates everything, including values that are objects and non-enumerable properties.

    Options:

    • symbols: (boolean) Whether to clone symbol properties. Defaults to true.
    • shallow: (array of strings | boolean)
      • An array of dot-separated or array-based key paths to shallow copy from obj instead of deep.
      • true to shallow copy all object properties (useful for objects with non-enumerable properties and prototypes).
    const nestedObj = {
        w: /^something$/gi,
        x: {
            a: [1, 2, 3],
            b: 123456,
            c: new Date(),
        },
        y: 'y',
        z: new Date(),
    };
    
    // Deep clone
    const copy = Hoek.clone(nestedObj);
    
    // Shallow clone specific keys
    const shallowCopy = Hoek.clone(nestedObj, { shallow: ['x'] });