@hapi/hoek
Advanced tools
Comparing version 6.2.4 to 7.0.0
@@ -241,3 +241,3 @@ 'use strict'; | ||
if (options.symbols) { | ||
if (options.symbols !== false) { // Defaults to true | ||
const objSymbols = getOwnPropertySymbols(obj); | ||
@@ -244,0 +244,0 @@ const refSymbols = new Set(getOwnPropertySymbols(ref)); |
@@ -32,3 +32,3 @@ /** | ||
@default false | ||
@default true | ||
*/ | ||
@@ -44,3 +44,3 @@ readonly symbols?: boolean; | ||
@param obj - The value being cloned. | ||
@param options - The second number to add. | ||
@param options - Optional settings. | ||
@@ -65,5 +65,12 @@ @returns A deep clone of `obj`. | ||
@default false | ||
@default true | ||
*/ | ||
readonly symbols?: boolean; | ||
/** | ||
Shallow clone the specified keys. | ||
@default undefined | ||
*/ | ||
readonly shallow?: string[] | string[][]; | ||
} | ||
@@ -78,45 +85,68 @@ } | ||
@param source - The object used to copy properties from. | ||
@param isNullOverride - When true, null value from `source` overrides existing value in `target`. Defaults to true. | ||
@param isMergeArrays - When true, array value from `source` is merged with the existing value in `target`. Defaults to true. | ||
@param options - Optional settings. | ||
@returns The `target` object. | ||
*/ | ||
export function merge<T1 extends object, T2 extends object>(target: T1, source: T2, isNullOverride?: boolean, isMergeArrays?: boolean): T1 & T2; | ||
export function merge<T1 extends object, T2 extends object>(target: T1, source: T2, options?: merge.Options): T1 & T2; | ||
declare namespace merge { | ||
/** | ||
Apply options to a copy of the defaults. | ||
interface Options { | ||
@param defaults - An object with the default values to use of `options` does not contain the same keys. | ||
@param options - The options used to override the `defaults`. | ||
@param isNullOverride - When true, null value from `options` overrides existing value in `defaults`. Defaults to false. | ||
/** | ||
When true, null value from `source` overrides existing value in `target`. | ||
@returns A copy of `defaults` with `options` keys overriding any conflicts. | ||
*/ | ||
export function applyToDefaults<T extends object>(defaults: Partial<T>, options: Partial<T> | boolean | null, isNullOverride?: boolean): Partial<T>; | ||
@default true | ||
*/ | ||
readonly nullOverride?: boolean; | ||
/** | ||
When true, array value from `source` is merged with the existing value in `target`. | ||
/** | ||
Clone an object or array with specific keys shallowly cloned. | ||
@default false | ||
*/ | ||
readonly mergeArrays?: boolean; | ||
@param obj - The object being cloned. | ||
@param keys - An array of string keys indicating which `obj` properties to shallow copy instead of deep clone. Use dot-notation to indicate nested keys (e.g. "a.b"). | ||
/** | ||
Compare symbol properties. | ||
@returns A deep clone of `obj` with the requested `keys` shallowly cloned. | ||
*/ | ||
export function cloneWithShallow<T>(obj: T, keys: string[], options?: clone.Options): T; | ||
@default true | ||
*/ | ||
readonly symbols?: boolean; | ||
} | ||
} | ||
/** | ||
Apply options to a copy of the defaults with specific keys shallowly cloned. | ||
Apply source to a copy of the defaults. | ||
@param defaults - An object with the default values to use of `options` does not contain the same keys. | ||
@param options - The options used to override the `defaults`. | ||
@param keys - An array of string keys indicating which `options` properties to shallow copy instead of deep clone. Use dot-notation to indicate nested keys (e.g. "a.b"). | ||
@param source - The source used to override the `defaults`. | ||
@param options - Optional settings. | ||
@returns A copy of `defaults` with `options` keys overriding any conflicts. | ||
@returns A copy of `defaults` with `source` keys overriding any conflicts. | ||
*/ | ||
export function applyToDefaultsWithShallow<T extends object>(defaults: Partial<T>, options: Partial<T> | boolean | null, keys: string[]): Partial<T>; | ||
export function applyToDefaults<T extends object>(defaults: Partial<T>, source: Partial<T> | boolean | null, options?: applyToDefaults.Options): Partial<T>; | ||
declare namespace applyToDefaults { | ||
interface Options { | ||
/** | ||
When true, null value from `source` overrides existing value in `target`. | ||
@default true | ||
*/ | ||
readonly nullOverride?: boolean; | ||
/** | ||
Shallow clone the specified keys. | ||
@default undefined | ||
*/ | ||
readonly shallow?: string[] | string[][]; | ||
} | ||
} | ||
/** | ||
@@ -127,8 +157,8 @@ Find the common unique items in two arrays. | ||
@param array2 - The second array to compare. | ||
@param justFirst - If true, return the first overlapping value. Defaults to false. | ||
@param options - Optional settings. | ||
@return - An array of the common items. If `justFirst` is true, returns the first common item. | ||
*/ | ||
export function intersect<T1, T2>(array1: intersect.Array<T1>, array2: intersect.Array<T2>, justFirst?: false): Array<T1 | T2>; | ||
export function intersect<T1, T2>(array1: intersect.Array<T1>, array2: intersect.Array<T2>, justFirst: true): T1 | T2; | ||
export function intersect<T1, T2>(array1: intersect.Array<T1>, array2: intersect.Array<T2>, options?: intersect.Options): Array<T1 | T2>; | ||
export function intersect<T1, T2>(array1: intersect.Array<T1>, array2: intersect.Array<T2>, options?: intersect.Options): T1 | T2; | ||
@@ -138,2 +168,12 @@ declare namespace intersect { | ||
type Array<T> = ArrayLike<T> | Set<T> | null; | ||
interface Options { | ||
/** | ||
When true, return the first overlapping value. | ||
@default false | ||
*/ | ||
readonly first?: boolean; | ||
} | ||
} | ||
@@ -189,3 +229,3 @@ | ||
@default false | ||
@default true | ||
*/ | ||
@@ -192,0 +232,0 @@ readonly symbols?: boolean; |
184
lib/index.js
@@ -36,2 +36,6 @@ 'use strict'; | ||
if (options.shallow) { | ||
return internals.cloneWithShallow(obj, options); | ||
} | ||
const seen = _seen || new Map(); | ||
@@ -138,9 +142,63 @@ | ||
return options.symbols ? Reflect.ownKeys(obj) : Object.getOwnPropertyNames(obj); | ||
return options.symbols !== false ? Reflect.ownKeys(obj) : Object.getOwnPropertyNames(obj); // Defaults to true | ||
}; | ||
internals.cloneWithShallow = function (source, options) { | ||
const keys = options.shallow; | ||
options = { ...options, shallow: false }; | ||
const storage = internals.store(source, keys); // Move shallow copy items to storage | ||
const copy = exports.clone(source, options); // Deep copy the rest | ||
internals.restore(copy, source, storage); // Shallow copy the stored items and restore | ||
return copy; | ||
}; | ||
internals.store = function (source, keys) { | ||
const storage = new Map(); | ||
for (let i = 0; i < keys.length; ++i) { | ||
const key = keys[i]; | ||
const value = exports.reach(source, key); | ||
if (typeof value === 'object' || | ||
typeof value === 'function') { | ||
storage.set(key, value); | ||
internals.reachSet(source, key, undefined); | ||
} | ||
} | ||
return storage; | ||
}; | ||
internals.restore = function (copy, source, storage) { | ||
for (const [key, value] of storage) { | ||
internals.reachSet(copy, key, value); | ||
internals.reachSet(source, key, value); | ||
} | ||
}; | ||
internals.reachSet = function (obj, key, value) { | ||
const path = Array.isArray(key) ? key : key.split('.'); | ||
let ref = obj; | ||
for (let i = 0; i < path.length; ++i) { | ||
const segment = path[i]; | ||
if (i + 1 === path.length) { | ||
ref[segment] = value; | ||
} | ||
ref = ref[segment]; | ||
} | ||
}; | ||
// Merge all the properties of source into target, source wins in conflict, and by default null and undefined from source are applied | ||
exports.merge = function (target, source, isNullOverride = true, isMergeArrays = true) { | ||
exports.merge = function (target, source, options) { | ||
@@ -154,5 +212,7 @@ exports.assert(target && typeof target === 'object', 'Invalid target value: must be an object'); | ||
options = { nullOverride: true, mergeArrays: true, ...options }; | ||
if (Array.isArray(source)) { | ||
exports.assert(Array.isArray(target), 'Cannot merge array onto an object'); | ||
if (!isMergeArrays) { | ||
if (!options.mergeArrays) { | ||
target.length = 0; // Must not change target assignment | ||
@@ -162,3 +222,3 @@ } | ||
for (let i = 0; i < source.length; ++i) { | ||
target.push(exports.clone(source[i])); | ||
target.push(exports.clone(source[i], { symbols: options.symbols })); | ||
} | ||
@@ -169,3 +229,3 @@ | ||
const keys = internals.keys(source); | ||
const keys = internals.keys(source, options); | ||
for (let i = 0; i < keys.length; ++i) { | ||
@@ -190,6 +250,6 @@ const key = keys[i]; | ||
target[key] = exports.clone(value); | ||
target[key] = exports.clone(value, { symbols: options.symbols }); | ||
} | ||
else { | ||
exports.merge(target[key], value, isNullOverride, isMergeArrays); | ||
exports.merge(target[key], value, options); | ||
} | ||
@@ -203,3 +263,3 @@ } | ||
} | ||
else if (isNullOverride) { | ||
else if (options.nullOverride) { | ||
target[key] = value; | ||
@@ -214,103 +274,47 @@ } | ||
// Apply options to a copy of the defaults | ||
// Apply source to a copy of the defaults | ||
exports.applyToDefaults = function (defaults, options, isNullOverride = false) { | ||
exports.applyToDefaults = function (defaults, source, options) { | ||
exports.assert(defaults && typeof defaults === 'object', 'Invalid defaults value: must be an object'); | ||
exports.assert(!options || options === true || typeof options === 'object', 'Invalid options value: must be true, falsy or an object'); | ||
exports.assert(!source || source === true || typeof source === 'object', 'Invalid source value: must be true, falsy or an object'); | ||
exports.assert(options === undefined || options && typeof options === 'object', 'Invalid options: must be an object'); | ||
if (!options) { // If no options, return null | ||
if (!source) { // If no source, return null | ||
return null; | ||
} | ||
const copy = exports.clone(defaults); | ||
if (options && | ||
options.shallow) { | ||
if (options === true) { // If options is set to true, use defaults | ||
return copy; | ||
return internals.applyToDefaultsWithShallow(defaults, source, options); | ||
} | ||
return exports.merge(copy, options, isNullOverride, false); | ||
}; | ||
const copy = exports.clone(defaults); | ||
// Clone an object except for the listed keys which are shallow copied | ||
exports.cloneWithShallow = function (source, keys, options) { | ||
if (!source || | ||
typeof source !== 'object') { | ||
return source; | ||
if (source === true) { // If source is set to true, use defaults | ||
return copy; | ||
} | ||
const storage = internals.store(source, keys); // Move shallow copy items to storage | ||
const copy = exports.clone(source, options); // Deep copy the rest | ||
internals.restore(copy, source, storage); // Shallow copy the stored items and restore | ||
return copy; | ||
const nullOverride = options && options.nullOverride !== undefined ? options.nullOverride : false; | ||
return exports.merge(copy, source, { nullOverride, mergeArrays: false }); | ||
}; | ||
internals.store = function (source, keys) { | ||
internals.applyToDefaultsWithShallow = function (defaults, source, options) { | ||
const storage = new Map(); | ||
for (let i = 0; i < keys.length; ++i) { | ||
const key = keys[i]; | ||
const value = exports.reach(source, key); | ||
if (typeof value === 'object' || | ||
typeof value === 'function') { | ||
const keys = options.shallow; | ||
exports.assert(Array.isArray(keys), 'Invalid keys'); | ||
storage.set(key, value); | ||
internals.reachSet(source, key, undefined); | ||
} | ||
} | ||
options = { ...options, shallow: false }; | ||
return storage; | ||
}; | ||
const copy = exports.clone(defaults, { shallow: keys }); | ||
internals.restore = function (copy, source, storage) { | ||
for (const [key, value] of storage) { | ||
internals.reachSet(copy, key, value); | ||
internals.reachSet(source, key, value); | ||
} | ||
}; | ||
internals.reachSet = function (obj, key, value) { | ||
const path = Array.isArray(key) ? key : key.split('.'); | ||
let ref = obj; | ||
for (let i = 0; i < path.length; ++i) { | ||
const segment = path[i]; | ||
if (i + 1 === path.length) { | ||
ref[segment] = value; | ||
} | ||
ref = ref[segment]; | ||
} | ||
}; | ||
// Apply options to defaults except for the listed keys which are shallow copied from option without merging | ||
exports.applyToDefaultsWithShallow = function (defaults, options, keys) { | ||
exports.assert(defaults && typeof defaults === 'object', 'Invalid defaults value: must be an object'); | ||
exports.assert(!options || options === true || typeof options === 'object', 'Invalid options value: must be true, falsy or an object'); | ||
exports.assert(keys && Array.isArray(keys), 'Invalid keys'); | ||
if (!options) { // If no options, return null | ||
return null; | ||
} | ||
const copy = exports.cloneWithShallow(defaults, keys); | ||
if (options === true) { // If options is set to true, use defaults | ||
if (source === true) { // If source is set to true, use defaults | ||
return copy; | ||
} | ||
const storage = internals.store(options, keys); // Move shallow copy items to storage | ||
exports.merge(copy, options, false, false); // Deep copy the rest | ||
internals.restore(copy, options, storage); // Shallow copy the stored items and restore | ||
const storage = internals.store(source, keys); // Move shallow copy items to storage | ||
exports.merge(copy, source, { mergeArrays: false, nullOverride: false }); // Deep copy the rest | ||
internals.restore(copy, source, storage); // Shallow copy the stored items and restore | ||
return copy; | ||
@@ -322,3 +326,3 @@ }; | ||
exports.intersect = function (array1, array2, justFirst = false) { | ||
exports.intersect = function (array1, array2, options = {}) { | ||
@@ -328,3 +332,3 @@ if (!array1 || | ||
return (justFirst ? null : []); | ||
return (options.first ? null : []); | ||
} | ||
@@ -339,3 +343,3 @@ | ||
if (justFirst) { | ||
if (options.first) { | ||
return value; | ||
@@ -349,3 +353,3 @@ } | ||
return (justFirst ? null : common); | ||
return (options.first ? null : common); | ||
}; | ||
@@ -352,0 +356,0 @@ |
{ | ||
"name": "@hapi/hoek", | ||
"description": "General purpose node utilities", | ||
"version": "6.2.4", | ||
"version": "7.0.0", | ||
"repository": "git://github.com/hapijs/hoek", | ||
@@ -6,0 +6,0 @@ "main": "lib/index.js", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
43100
1140