Object property traversal and template replacement utilities using dot notation and bracket syntax for nested data access with support for arrays, functions, and iterables.
Converts an object key chain string or array to reference, providing safe traversal of nested object properties.
/**
* Convert an object key chain string to reference
* @param obj - The object from which to look up the value
* @param chain - The string path or array of keys. Negative numbers work like negative array indices
* @param options - Optional settings for traversal behavior
* @returns The value referenced by the chain if found, otherwise undefined
*/
function reach(obj: object | null, chain: string | (string | number)[] | false | null | undefined, options?: reach.Options): any;
namespace reach {
interface Options {
/** String to split chain path on. Defaults to '.' */
readonly separator?: string;
/** Value to return if the path or value is not present. No default value */
readonly default?: any;
/** If true, will throw an error on missing member in the chain. Defaults to false */
readonly strict?: boolean;
/** If true, allows traversing functions for properties. false will throw error if function is part of chain. Defaults to true */
readonly functions?: boolean;
/** If true, allows traversing Set and Map objects for properties. Defaults to false */
readonly iterables?: boolean;
}
}Usage Examples:
import { reach } from "@hapi/hoek";
// Basic dot notation traversal
const obj = { a: { b: { c: 1 } } };
const value = reach(obj, 'a.b.c'); // 1
// Array-style key specification
const arrayKeys = reach(obj, ['a', 'b', 'c']); // 1
// Array index access including negative indices
const arrayObj = { a: { b: [2, 3, 6] } };
const lastItem = reach(arrayObj, ['a', 'b', -1]); // 6
const firstItem = reach(arrayObj, 'a.b.0'); // 2
// Default values for missing paths
const missing = reach(obj, 'a.x.y', { default: 'not found' }); // 'not found'
// Custom separator
const colonObj = { 'user:profile:name': 'Alice' };
const customSep = reach(colonObj, 'user:profile:name', { separator: ':' }); // Won't work as expected
// Better approach:
const nestedObj = { user: { profile: { name: 'Alice' } } };
const name = reach(nestedObj, 'user:profile:name', { separator: ':' }); // 'Alice'
// Strict mode throws on missing properties
try {
reach(obj, 'a.missing.path', { strict: true }); // Throws error
} catch (error) {
console.log('Path not found');
}
// Function traversal
const funcObj = {
getValue: function() { return { nested: 'value' }; }
};
const funcResult = reach(funcObj, 'getValue.nested', { functions: true }); // 'value'
// Null/undefined chain returns the object itself
const self = reach(obj, null); // obj
const selfUndefined = reach(obj, undefined); // obj
const selfFalse = reach(obj, false); // objReplaces string parameters (using format "{path.to.key}") with their corresponding object key values using the reach functionality.
/**
* Replace string parameters (using format "{path.to.key}") with their corresponding object key values using Hoek.reach()
* @param obj - The object from which to look up the value
* @param template - The string containing {} enclosed key paths to be replaced
* @param options - Optional reach.Options for path traversal behavior
* @returns The template string with {} enclosed keys replaced with looked-up values
*/
function reachTemplate(obj: object | null, template: string, options?: reach.Options): string;Usage Examples:
import { reachTemplate } from "@hapi/hoek";
// Basic template replacement
const data = {
user: { name: 'Alice', id: 123 },
action: 'login',
timestamp: '2023-01-01'
};
const template = 'User {user.name} performed {action} at {timestamp}';
const result = reachTemplate(data, template);
// Result: 'User Alice performed login at 2023-01-01'
// Mathematical expressions in templates
const mathData = { a: { b: { c: 1 } } };
const mathTemplate = '1+{a.b.c}=2';
const mathResult = reachTemplate(mathData, mathTemplate);
// Result: '1+1=2'
// Multiple occurrences of same path
const repeatTemplate = '{user.name} says hello to {user.name}';
const repeatResult = reachTemplate(data, repeatTemplate);
// Result: 'Alice says hello to Alice'
// Array access in templates
const arrayData = {
users: ['Alice', 'Bob', 'Charlie'],
scores: [100, 85, 92]
};
const arrayTemplate = 'Winner: {users.0} with score {scores.0}';
const arrayResult = reachTemplate(arrayData, arrayTemplate);
// Result: 'Winner: Alice with score 100'
// Nested object templates
const nestedData = {
config: {
server: { host: 'localhost', port: 8080 },
database: { name: 'myapp' }
}
};
const nestedTemplate = 'Server running at {config.server.host}:{config.server.port} using {config.database.name}';
const nestedResult = reachTemplate(nestedData, nestedTemplate);
// Result: 'Server running at localhost:8080 using myapp'
// Missing values are replaced with empty string
const missingTemplate = 'User {user.name} has {user.missing} points';
const missingResult = reachTemplate(data, missingTemplate);
// Result: 'User Alice has points'
// Custom separator with reach options
const customData = { 'level1': { 'level2': { 'value': 'found' } } };
const customTemplate = 'Value: {level1:level2:value}';
const customResult = reachTemplate(customData, customTemplate, { separator: ':' });
// Result: 'Value: found'Important Notes:
reach(), supporting all its options{} syntax is specifically for path replacement - literal braces need to be escaped if neededreach.Options are supported for customizing path traversal behavior{path} found in the string