hoek provides several helpful methods for objects and arrays.
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 totrue
.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;
- an array of object key strings (dot-separated or array-based key paths) to shallow copy from
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:
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 all the properties of source into target where:
target
- the object onto which the properties ofsource
are copied to.source
- the object copied ontotarget
.options
- optional settings:nullOverride
- iftrue
, anull
value in the source overrides any existing value in thedefaults
. Iffalse
,null
values in thesource
are ignored. Defaults totrue
.mergeArrays
- iftrue
, array values fromsource
are appended to existing array values intarget
. Defaults totrue
.symbols
- clone symbol properties. Defaults totrue
.
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
.
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]
Apply source to a copy of the defaults where:
defaults
- the default object to clone and then applysource
onto.source
- the object applied to thedefaults
.options
- optional settings:nullOverride
- iftrue
, anull
value in the source overrides any existing value in thedefaults
. Iffalse
,null
values in thesource
are ignored. Defaults tofalse
.shallow
- an array of dot-separated or array-based key paths to shallow copy values insource
.
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
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
const defaults = {
db: {
server: {
host: "localhost",
port: 8000
},
name: 'example'
}
};
const source = { 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' } }
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
- whentrue
, function values are deep compared using their source code and object properties. Defaults tofalse
.part
- whentrue
, allows a partial match where some ofb
is present ina
. Defaults tofalse
.prototype
- whenfalse, 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
- whenfalse
, symbol properties are ignored. Defaults totrue
.
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
Find the common unique items betwee two arrays where:
array1
- the first array.array2
- the second array.options
- optional settings:first
- iftrue
, return only the first intersecting item. Defaults tofalse
.
const array1 = [1, 2, 3];
const array2 = [1, 4, 5];
const newArray = Hoek.intersect(array1, array2); // results in [1]
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 theref
value. Ifref
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
- iftrue
, performed a deep comparison of the values.once
- iftrue
, allows only one occurrence of each value.only
- iftrue
, does not allow values not explicitly listed.part
- iftrue
, allows partial match of the values (at least one must always match).symbols
- clone symbol properties. Defaults totrue
.
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.
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 an array
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]
Converts an object key chain string or array to reference
options
- optional settingsseparator
- string to split chain path on, defaults to '.'default
- value to return if the path or value is not present, default isundefined
strict
- iftrue
, will throw an error on missing member, default isfalse
functions
- iftrue
, allow traversing functions for properties.false
will throw an error if a function is part of the chain. Defaults totrue
.iterables
- iftrue
, allows traversing Set and Map objects.false
will result inundefined
return value is the chain contains any Set or Map objects. Note that enablingiterables
can impact performance by up to 10% for all calls regardless of the presence of Set or Map objects. Defaults tofalse
.
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.
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
Replaces string parameters ({name}
) with their corresponding object key values by applying the
reach()
method where:
obj
- the context object used for key lookup.template
- a string containing{}
parameters.options
- optionalreach()
options.
const template = '1+{a.b.c}=2';
const obj = { a: { b: { c: 1 } } };
Hoek.reachTemplate(obj, template); // returns '1+1=2'
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.
const a = {};
a.b = a;
Hoek.stringify(a); // Returns '[Cannot display object: Converting circular structure to JSON]'
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.
hoek provides convenient methods for escaping html characters. The escaped characters are as followed:
internals.htmlEscaped = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": ''',
'`': '`'
};
const string = '<html> hey </html>';
const escapedString = Hoek.escapeHtml(string); // returns <html> hey </html>
Escape attribute value for use in HTTP header
const a = Hoek.escapeHeaderAttribute('I said "go w\\o me"'); //returns I said \"go w\\o me\"
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.
const lineSeparator = String.fromCharCode(0x2028);
const a = Hoek.escapeJson('I said <script>confirm(&).' + lineSeparator); //returns I said \\u003cscript\\u003econfirm(\\u0026).\\u2028
Escape string for Regex construction
const a = Hoek.escapeRegex('4^f$s.4*5+-_?%=#!:@|~\\/`"(>)[<]d{}s,'); // returns 4\^f\$s\.4\*5\+\-_\?%\=#\!\:@\|~\\\/`"\(>\)\[<\]d\{\}s\,
const a = 1, b = 2;
Hoek.assert(a === b, 'a should equal b'); // Throws 'a should equal b'
Note that you may also pass an already created Error object as the second parameter, and assert
will throw that object.
const a = 1, b = 2;
Hoek.assert(a === b, new Error('a should equal b')); // Throws the given error object
Returns a new function that can be run multiple times, but makes sure fn
is only run once.
const myFn = function () {
console.log('Ran myFn');
};
const onceFn = Hoek.once(myFn);
onceFn(); // results in "Ran myFn"
onceFn(); // results in undefined
A simple no-op function. It does nothing at all.
Resolve the promise after timeout
milliseconds with the provided returnValue
.
await Hoek.wait(2000); // waits for 2 seconds
const timeout = Hoek.wait(1000, 'timeout'); // resolves after 1s with 'timeout'
A no-op Promise. Does nothing.
Determines if an item is a promise where:
promise
- the item being tested.
Returns true
is the item is a promise, otherwise false
.