### Object **hoek** provides several helpful methods for objects and arrays. #### clone(obj, [options]) Clones an object or an array. A *deep copy* is made (duplicates everything, including values that are objects, as well as non-enumerable properties) where: - `obj` - the object to be cloned. - `options` - optional settings: - `symbols` - clone symbol properties. Defaults to `true`. - `shallow` - one of: - an array of object key strings (dot-separated or array-based key paths) to shallow copy from `obj` instead of deep. - `true` to shallow copy all object properties. Used to shallow copy an object with non-enumerable properties and prototype; ```javascript const nestedObj = { w: /^something$/ig, x: { a: [1, 2, 3], b: 123456, c: new Date() }, y: 'y', z: new Date() }; const copy = Hoek.clone(nestedObj); copy.x.b = 100; console.log(copy.y); // results in 'y' console.log(nestedObj.x.b); // results in 123456 console.log(copy.x.b); // results in 100 ``` Clones an object or array excluding some keys which are shallow copied: ```javascript const nestedObj = { w: /^something$/ig, x: { a: [1, 2, 3], b: 123456, c: new Date() }, y: 'y', z: new Date() }; const copy = Hoek.clone(nestedObj, { shallow: ['x'] }); copy.x.b = 100; console.log(copy.y); // results in 'y' console.log(nestedObj.x.b); // results in 100 console.log(copy.x.b); // results in 100 ``` #### merge(target, source, [options]) Merge all the properties of source into target where: - `target` - the object onto which the properties of `source` are copied to. - `source` - the object copied onto `target`. - `options` - optional settings: - `nullOverride` - if `true`, a `null` value in the source overrides any existing value in the `defaults`. If `false`, `null` values in the `source` are ignored. Defaults to `true`. - `mergeArrays` - if `true`, array values from `source` are appended to existing array values in `target`. Defaults to `true`. - `symbols` - clone symbol properties. Defaults to `true`. Note that source wins in conflict, and by default null and undefined from source are applied. Merge is destructive where the target is modified. For non destructive merge, use `applyToDefaults`. ```javascript const target = {a: 1, b : 2}; const source = {a: 0, c: 5}; const source2 = {a: null, c: 5}; Hoek.merge(target, source); // results in {a: 0, b: 2, c: 5} Hoek.merge(target, source2); // results in {a: null, b: 2, c: 5} Hoek.merge(target, source2, { nullOverride: false} ); // results in {a: 1, b: 2, c: 5} const targetArray = [1, 2, 3]; const sourceArray = [4, 5]; Hoek.merge(targetArray, sourceArray); // results in [1, 2, 3, 4, 5] Hoek.merge(targetArray, sourceArray, { mergeArrays: false }); // results in [4, 5] ``` #### applyToDefaults(defaults, source, [options]) Apply source to a copy of the defaults where: - `defaults` - the default object to clone and then apply `source` onto. - `source` - the object applied to the `defaults`. - `options` - optional settings: - `nullOverride` - if `true`, a `null` value in the source overrides any existing value in the `defaults`. If `false`, `null` values in the `source` are ignored. Defaults to `false`. - `shallow` - an array of dot-separated or array-based key paths to shallow copy values in `source`. ```javascript const defaults = { host: "localhost", port: 8000 }; const source = { port: 8080 }; const config = Hoek.applyToDefaults(defaults, source); // results in { host: "localhost", port: 8080 } ``` Apply source with a null value to a copy of the defaults ```javascript const defaults = { host: "localhost", port: 8000 }; const source = { host: null, port: 8080 }; const config = Hoek.applyToDefaults(defaults, source, { nullOverride: true }); // results in { host: null, port: 8080 } ``` Apply source to a copy of the defaults where the shallow keys specified in the last parameter are shallow copied from source instead of merged ```javascript const defaults = { db: { server: { host: "localhost", port: 8000 }, name: 'example' } }; const source = { db: { server: { port: 8080 } } }; const config = Hoek.applyToDefaults(defaults, source, { shallow: ['db.server'] }); // results in { db: { server: { port: 8080 }, name: 'example' } } const config = Hoek.applyToDefaults(defaults, source, { shallow: [['db', 'server']] }); // results in { db: { server: { port: 8080 }, name: 'example' } } ``` #### deepEqual(a, b, [options]) Performs a deep comparison of the two values including support for circular dependencies, prototype, and enumerable properties, where: - `a` - the first value. - `b` - the second value. - `options` - optional settings: - `deepFunction` - when `true`, function values are deep compared using their source code and object properties. Defaults to `false`. - `part` - when `true`, allows a partial match where some of `b` is present in `a`. Defaults to `false`. - `prototype` - when `false, prototype comparisons are skipped. Defaults to `true`. - `skip` - an array of key name strings to skip comparing. The keys can be found in any level of the object. Note that both values must contain the key - only the value comparison is skipped. Only applies to plain objects and deep functions (not to map, sets, etc.). Defaults to no skipping. - `symbols` - when `false`, symbol properties are ignored. Defaults to `true`. ```javascript Hoek.deepEqual({ a: [1, 2], b: 'string', c: { d: true } }, { a: [1, 2], b: 'string', c: { d: true } }); //results in true Hoek.deepEqual(Object.create(null), {}, { prototype: false }); //results in true Hoek.deepEqual(Object.create(null), {}); //results in false ``` #### intersect(array1, array2, [options]) Find the common unique items betwee two arrays where: - `array1` - the first array. - `array2` - the second array. - `options` - optional settings: - `first` - if `true`, return only the first intersecting item. Defaults to `false`. ```javascript const array1 = [1, 2, 3]; const array2 = [1, 4, 5]; const newArray = Hoek.intersect(array1, array2); // results in [1] ``` #### contain(ref, values, [options]) Tests if the reference value contains the provided values where: - `ref` - the reference string, array, or object. - `values` - a single or array of values to find within the `ref` value. If `ref` is an object, `values` can be a key name, an array of key names, or an object with key-value pairs to compare. - `options` - an optional object with the following optional settings: - `deep` - if `true`, performed a deep comparison of the values. - `once` - if `true`, allows only one occurrence of each value. - `only` - if `true`, does not allow values not explicitly listed. - `part` - if `true`, allows partial match of the values (at least one must always match). - `symbols` - clone symbol properties. Defaults to `true`. Note: comparing a string to overlapping values will result in failed comparison (e.g. `contain('abc', ['ab', 'bc'])`). Also, if an object key's value does not match the provided value, `false` is returned even when `part` is specified. ```javascript 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 Hoek.contain({ a: 1, b: 2, c: 3 }, { a: 1, d: 4 }, { part: true }); // true ``` #### flatten(array, [target]) Flatten an array ```javascript const array = [1, [2, 3]]; const flattenedArray = Hoek.flatten(array); // results in [1, 2, 3] array = [1, [2, 3]]; target = [4, [5]]; flattenedArray = Hoek.flatten(array, target); // results in [4, [5], 1, 2, 3] ``` #### reach(obj, chain, [options]) Converts an object key chain string or array to reference - `options` - optional settings - `separator` - string to split chain path on, defaults to '.' - `default` - value to return if the path or value is not present, default is `undefined` - `strict` - if `true`, will throw an error on missing member, default is `false` - `functions` - if `true`, allow traversing functions for properties. `false` will throw an error if a function is part of the chain. Defaults to `true`. - `iterables` - if `true`, allows traversing Set and Map objects. `false` will result in `undefined` return value is the chain contains any Set or Map objects. Note that enabling `iterables` can impact performance by up to 10% for all calls regardless of the presence of Set or Map objects. Defaults to `false`. A chain can be a string that will be split into key names using `separator`, or an array containing each individual key name. A chain including negative numbers will work like negative indices on an array. If chain is `null`, `undefined` or `false`, the object itself will be returned. ```javascript const chain = 'a.b.c'; const obj = {a : {b : { c : 1}}}; Hoek.reach(obj, chain); // returns 1 const chain = ['a', 'b', -1]; const obj = {a : {b : [2,3,6]}}; Hoek.reach(obj, chain); // returns 6 ``` #### reachTemplate(obj, template, [options]) Replaces string parameters (`{name}`) with their corresponding object key values by applying the [`reach()`](#reachobj-chain-options) method where: - `obj` - the context object used for key lookup. - `template` - a string containing `{}` parameters. - `options` - optional [`reach()`](#reachobj-chain-options) options. ```javascript const template = '1+{a.b.c}=2'; const obj = { a: { b: { c: 1 } } }; Hoek.reachTemplate(obj, template); // returns '1+1=2' ``` #### stringify(...args) Converts an object to string using the built-in `JSON.stringify()` method with the difference that any errors are caught and reported back in the form of the returned string. Used as a shortcut for displaying information to the console (e.g. in error message) without the need to worry about invalid conversion. ```javascript const a = {}; a.b = a; Hoek.stringify(a); // Returns '[Cannot display object: Converting circular structure to JSON]' ``` ### Bench Same as Timer with the exception that `ts` stores the internal node clock which is not related to `Date.now()` and cannot be used to display human-readable timestamps. More accurate for benchmarking or internal timers. ### Escaping Characters **hoek** provides convenient methods for escaping html characters. The escaped characters are as followed: ```javascript internals.htmlEscaped = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''', '`': '`' }; ``` #### escapeHtml(string) ```javascript const string = ' hey '; const escapedString = Hoek.escapeHtml(string); // returns <html> hey </html> ``` #### escapeHeaderAttribute(attribute) Escape attribute value for use in HTTP header ```javascript const a = Hoek.escapeHeaderAttribute('I said "go w\\o me"'); //returns I said \"go w\\o me\" ``` #### escapeJson(string) Unicode escapes the characters `<`, `>`, and `&` to prevent mime-sniffing older browsers mistaking JSON as HTML, and escapes line and paragraph separators for JSONP and script contexts. ```javascript const lineSeparator = String.fromCharCode(0x2028); const a = Hoek.escapeJson('I said