node-vitals
Version:
Do more with less. A simple, high-performing, functional JavaScript library.
1,108 lines (957 loc) • 32 kB
JavaScript
/**
* -----------------------------------------------------------------------------
* VITALS METHOD: amend
* -----------------------------------------------------------------------------
* @section strict
* @version 4.1.3
* @see [vitals.amend]{@link https://github.com/imaginate/vitals/wiki/vitals.amend}
*
* @author Adam Smith <adam@imaginate.life> (https://github.com/imaginate)
* @copyright 2017 Adam A Smith <adam@imaginate.life> (https://github.com/imaginate)
*
* Annotations:
* @see [JSDoc3](http://usejsdoc.org)
* @see [Closure Compiler JSDoc Syntax](https://developers.google.com/closure/compiler/docs/js-for-compiler)
*/
'use strict';
var newErrorMaker = require('./helpers/new-error-maker.js');
var splitKeys = require('./helpers/split-keys.js');
var cloneObj = require('./helpers/clone-obj.js');
var merge = require('./helpers/merge.js');
var own = require('./helpers/own.js');
var _is = require('./helpers/is.js');
var is = require('./is.js');
////////////////////////////////////////////////////////////////////////////////
// VITALS METHOD: amend
////////////////////////////////////////////////////////////////////////////////
var amend = (function amendPrivateScope() {
//////////////////////////////////////////////////////////
// PUBLIC METHODS
// - amend
// - amend.config
// - amend.property (amend.prop)
// - amend.property.config (amend.prop.config)
// - amend.properties (amend.props)
// - amend.properties.config (amend.props.config)
//////////////////////////////////////////////////////////
/**
* A shortcut for [Object.defineProperties](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties)
* that includes easier value assignment, strong type assignment, and more
* flexible default descriptor options.
*
* @public
* @param {!Object} obj
* @param {!(Object<string, *>|Array<string>|string)} props - The details for
* the props param are as follows (per props type):
* - object: Must be `propName => propVal` or `propName => propDescriptor`.
* - array: An array of key names to define.
* - string: Converted to an array of key names using one of the following
* values as the separator (values listed in order of rank):
* -- `", "`
* -- `","`
* -- `"|"`
* -- `" "`
* @param {*=} val - Only use (and required) if an array or string of keys is
* given for the props param. This param defines the value assigned for all
* keys regardless of descriptor type.
* @param {!Object=} descriptor - [default= { writable: true, enumerable: true, configurable: true }]
* The default descriptor values for each prop.
* @param {string=} strongType - If defined all new properties are assigned
* an accessor descriptor (unless assigned a data descriptor in the props
* param) that includes a setter (unless assigned a setter in the props
* param) that throws an error if the new property value fails a [vitals.is](https://github.com/imaginate/vitals/wiki/vitals.is)
* type test. The setter is as follows:
* ```
* prop.set = function set(newVal) {
* if ( !vitals.is(strongType, newVal) ) throw new TypeError("...");
* value = newVal;
* };
* ```
* @param {function(*, *): *=} setter - If defined all new properties are
* assigned an accessor descriptor (unless assigned a data descriptor in the
* props param) that includes a setter (unless assigned a setter in the
* props param) that sets the property to the value returned by this setter.
* Note that this setter function will receive two params, the new value and
* the current value. Also note that if the strongType param is defined this
* setter will not get called until the new value passes the type test.
* ```
* prop.set = function set(newVal) {
* if ( !vitals.is(strongType, newVal) ) throw new TypeError("...");
* value = setter(newVal, value);
* };
* ```
* @return {!Object}
*/
function amend(obj, props, val, descriptor, strongType, setter) {
/** @type {boolean} */
var isArr;
/** @type {!Array} */
var args;
/** @type {number} */
var len;
if ( !_is.obj(obj) ) throw _error.type('obj');
if ( _is.str(props) ) props = splitKeys(props);
if ( !_is.obj(props) ) throw _error.type('props');
isArr = _is.arr(props);
len = arguments.length;
if (isArr && len < 3) throw _error('No val defined');
if (!isArr && len > 2) {
setter = strongType;
strongType = descriptor;
descriptor = val;
val = undefined;
++len; // increase len for a valid _parseProps call
}
if (len === 4 || len === 5) {
args = _parseProps(len, descriptor, strongType, setter);
descriptor = args[0];
strongType = args[1];
setter = args[2];
}
if ( !is('!obj=', descriptor) ) throw _error.type('descriptor');
if ( !is('str=', strongType) ) throw _error.type('strongType');
if ( !is('func=', setter) ) throw _error.type('setter');
if (strongType) {
if ( isArr && !is(strongType + '=', val) ) {
throw _error('The val param is not a valid strongType');
}
if ( !isArr && !_strongTypeCheckProps(strongType, props) ) {
throw _error('A props value was not a valid strongType');
}
}
return _amendProps(obj, props, val, descriptor, strongType, setter);
}
/**
* A shortcut for [Object.defineProperties](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties)
* that only updates the descriptors of existing properties.
*
* @public
* @param {!Object} obj
* @param {!(Object<string, !Object>|Array<string>|string)} props - Details
* for the props param are as follows (per props type):
* - object: Must be `propName => propDescriptor` pairs.
* - array: An array of key names to update.
* - string: Converted to an array of key names using one of the following
* values as the separator (values listed in order of rank):
* -- `", "`
* -- `","`
* -- `"|"`
* -- `" "`
* @param {!Object=} descriptor - Only use (and required) if an array or
* string of keys is given for the props param.
* @return {!Object}
*/
amend.config = function amendConfig(obj, props, descriptor) {
if ( !_is.obj(obj) ) throw _error.type('obj', 'config');
if ( _is.str(props) ) props = splitKeys(props);
if ( !_is.obj(props) ) throw _error.type('props', 'config');
if ( _is.arr(props) ) {
if ( !_is.obj(descriptor) ) throw _error.type('descriptor', 'config');
props = _setupConfigs(props, descriptor);
}
else if ( !is('objMap', props) ) throw _error.type('props', 'config');
if ( !_hasKeys(obj, props) ) {
throw _error('A given prop was not defined in the obj', 'config');
}
return _amendConfigs(obj, props);
};
/**
* A shortcut for [Object.defineProperty](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty).
*
* @public
* @param {!Object} obj
* @param {string} key
* @param {*=} val - A val is required if a descriptor is not supplied.
* @param {!Object=} descriptor - [default= { writable: true, enumerable: true, configurable: true }]
* @param {string=} strongType - If defined the new property is assigned
* an accessor descriptor that includes a setter that throws an error if the
* new property value fails a [vitals.is](https://github.com/imaginate/vitals/wiki/vitals.is)
* type test. The setter is as follows:
* ```
* prop.set = function set(newVal) {
* if ( !vitals.is(strongType, newVal) ) throw new TypeError("...");
* value = newVal;
* };
* ```
* @param {function(*, *): *=} setter - If defined the new property is
* assigned an accessor descriptor that includes a setter that sets the
* property to the value returned by this setter method. The setter method
* will receive two params, the new value and the current value. If a
* strongType is defined this setter will not get called until the new value
* passes the type test.
* ```
* prop.set = function set(newVal) {
* if ( !vitals.is(strongType, newVal) ) throw new TypeError("...");
* value = setter(newVal, value);
* };
* ```
* @return {!Object}
*/
amend.property = function amendProperty(obj, key, val, descriptor, strongType, setter) {
/** @type {!Array} */
var args;
/** @type {number} */
var len;
if ( !_is.obj(obj) ) throw _error.type('obj', 'property');
if ( !_is.str(key) ) throw _error.type('key', 'property');
len = arguments.length;
if (len < 3) throw _error('No val or descriptor defined', 'property');
if (len > 2 && len < 6) {
args = _parseProp(len, val, descriptor, strongType, setter);
val = args[0];
descriptor = args[1];
strongType = args[2];
setter = args[3];
}
if ( !is('!obj=', descriptor) ) throw _error.type('descriptor', 'property');
if ( !is('str=', strongType) ) throw _error.type('strongType', 'property');
if ( !is('func=', setter) ) throw _error.type('setter', 'property');
if ( strongType && !is(strongType + '=', val) ) {
throw _error('The val param is not a valid strongType', 'property');
}
if ( descriptor && (strongType || setter) && own(descriptor, 'writable') ){
throw _error('A data descriptor may not be used with a strongType/setter', 'property');
}
return _amendProp(obj, key, val, descriptor, strongType, setter);
};
// define shorthand
amend.prop = amend.property;
/**
* A shortcut for [Object.defineProperty](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty)
* that only updates the descriptor of an existing property.
*
* @public
* @param {!Object} obj
* @param {string} key
* @param {!Object} descriptor
* @return {!Object}
*/
amend.property.config = function amendPropertyConfig(obj, key, descriptor) {
if ( !_is.obj(obj) ) throw _error.type('obj', 'property.config');
if ( !_is.str(key) ) throw _error.type('key', 'property.config');
if ( !_is.obj(descriptor)) throw _error.type('descriptor','property.config');
if ( !own(obj, key) ) {
throw _error('The key was not defined in the obj', 'property.config');
}
return _amendConfig(obj, key, descriptor);
};
// define shorthand
amend.prop.config = amend.property.config;
/**
* A shortcut for [Object.defineProperties](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties)
* that includes easier value assignment, strong type assignment, and more
* flexible default descriptor options.
*
* @public
* @param {!Object} obj
* @param {!(Object<string, *>|Array<string>|string)} props - The details for
* the props param are as follows (per props type):
* - object: Must be `propName => propVal` or `propName => propDescriptor`.
* - array: An array of key names to define.
* - string: Converted to an array of key names using one of the following
* values as the separator (values listed in order of rank):
* -- `", "`
* -- `","`
* -- `"|"`
* -- `" "`
* @param {*=} val - Only use (and required) if an array or string of keys is
* given for the props param. This param defines the value assigned for all
* keys regardless of descriptor type.
* @param {!Object=} descriptor - [default= { writable: true, enumerable: true, configurable: true }]
* The default descriptor values for each prop.
* @param {string=} strongType - If defined all new properties are assigned
* an accessor descriptor (unless assigned a data descriptor in the props
* param) that includes a setter (unless assigned a setter in the props
* param) that throws an error if the new property value fails a [vitals.is](https://github.com/imaginate/vitals/wiki/vitals.is)
* type test. The setter is as follows:
* ```
* prop.set = function set(newVal) {
* if ( !vitals.is(strongType, newVal) ) throw new TypeError("...");
* value = newVal;
* };
* ```
* @param {function(*, *): *=} setter - If defined all new properties are
* assigned an accessor descriptor (unless assigned a data descriptor in the
* props param) that includes a setter (unless assigned a setter in the
* props param) that sets the property to the value returned by this setter.
* Note that this setter function will receive two params, the new value and
* the current value. Also note that if the strongType param is defined this
* setter will not get called until the new value passes the type test.
* ```
* prop.set = function set(newVal) {
* if ( !vitals.is(strongType, newVal) ) throw new TypeError("...");
* value = setter(newVal, value);
* };
* ```
* @return {!Object}
*/
amend.properties = function amendProperties(obj, props, val, descriptor, strongType, setter) {
/** @type {boolean} */
var isArr;
/** @type {!Array} */
var args;
/** @type {number} */
var len;
if ( !_is.obj(obj) ) throw _error.type('obj', 'properties');
if ( _is.str(props) ) props = splitKeys(props);
if ( !_is.obj(props) ) throw _error.type('props', 'properties');
isArr = _is.arr(props);
len = arguments.length;
if (isArr && len < 3) throw _error('No val defined', 'properties');
if (!isArr && len > 2) {
setter = strongType;
strongType = descriptor;
descriptor = val;
val = undefined;
++len; // increase len for a valid _parseProps call
}
if (len === 4 || len === 5) {
args = _parseProps(len, descriptor, strongType, setter);
descriptor = args[0];
strongType = args[1];
setter = args[2];
}
if ( !is('!obj=', descriptor)) throw _error.type('descriptor','properties');
if ( !is('str=', strongType)) throw _error.type('strongType','properties');
if ( !is('func=', setter) ) throw _error.type('setter', 'properties');
if (strongType) {
if ( isArr && !is(strongType + '=', val) ) {
throw _error('The val param is not a valid strongType', 'properties');
}
if ( !isArr && !_strongTypeCheckProps(strongType, props) ) {
throw _error('A props value was not a valid strongType', 'properties');
}
}
return _amendProps(obj, props, val, descriptor, strongType, setter);
};
// define shorthand
amend.props = amend.properties;
/**
* A shortcut for [Object.defineProperties](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties)
* that only updates the descriptors of existing properties.
*
* @public
* @param {!Object} obj
* @param {!(Object<string, !Object>|Array<string>|string)} props - Details
* for the props param are as follows (per props type):
* - object: Must be `propName => propDescriptor` pairs.
* - array: An array of key names to update.
* - string: Converted to an array of key names using one of the following
* values as the separator (values listed in order of rank):
* -- `", "`
* -- `","`
* -- `"|"`
* -- `" "`
* @param {!Object=} descriptor - Only use (and required) if an array or
* string of keys is given for the props param.
* @return {!Object}
*/
amend.properties.config = function amendPropertiesConfig(obj, props, descriptor) {
if ( !_is.obj(obj) ) throw _error.type('obj', 'properties.config');
if ( _is.str(props) ) props = splitKeys(props);
if ( !_is.obj(props) ) throw _error.type('props', 'properties.config');
if ( _is.arr(props) ) {
if ( !_is.obj(descriptor) ) throw _error.type('descriptor', 'properties.config');
props = _setupConfigs(props, descriptor);
}
else if ( !is('objMap', props) ) throw _error.type('props', 'properties.config');
if ( !_hasKeys(obj, props) ) {
throw _error('A given prop was not defined in the obj', 'properties.config');
}
return _amendConfigs(obj, props);
};
// define shorthand
amend.props.config = amend.properties.config;
//////////////////////////////////////////////////////////
// PRIVATE METHODS - MAIN ARG PARSING
//////////////////////////////////////////////////////////
/**
* @private
* @param {number} len
* @param {*=} val
* @param {!Object=} descriptor
* @param {string=} strongType
* @param {function(*, *): *=} setter
* @return {!Array}
*/
function _parseProp(len, val, descriptor, strongType, setter) {
switch (len) {
case 4:
if ( _is.str(descriptor) ) {
strongType = descriptor;
descriptor = undefined;
}
else if ( _is.func(descriptor) ) {
setter = descriptor;
descriptor = undefined;
}
break;
case 5:
if ( _is.func(strongType) ) {
setter = strongType;
strongType = undefined;
if ( _is.str(descriptor) ) {
strongType = descriptor;
descriptor = undefined;
}
}
}
if ( _is.obj(val) && _isDescriptor(val) ) {
descriptor = val;
val = descriptor.value;
}
return [ val, descriptor, strongType, setter ];
}
/**
* @private
* @param {number} len
* @param {!Object=} descriptor
* @param {string=} strongType
* @param {function(*, *): *=} setter
* @return {!Array}
*/
function _parseProps(len, descriptor, strongType, setter) {
switch (len) {
case 4:
if ( _is.str(descriptor) ) {
strongType = descriptor;
descriptor = undefined;
}
else if ( _is.func(descriptor) ) {
setter = descriptor;
descriptor = undefined;
}
break;
case 5:
if ( _is.func(strongType) ) {
setter = strongType;
strongType = undefined;
if ( _is.str(descriptor) ) {
strongType = descriptor;
descriptor = undefined;
}
}
}
return [ descriptor, strongType, setter ];
}
/**
* @private
* @param {string} strongType
* @param {!Object} props
* @return {boolean}
*/
function _strongTypeCheckProps(strongType, props) {
/** @type {string} */
var key;
/** @type {*} */
var val;
strongType += '=';
for (key in props) {
if ( own(props, key) ) {
val = props[key];
if ( _is.obj(val) && _isDescriptor(val) ) {
if ( own(val, 'writable') ) continue;
val = val.value;
}
if ( !is(strongType, val) ) return false;
}
}
return true;
}
//////////////////////////////////////////////////////////
// PRIVATE METHODS - MAIN
//////////////////////////////////////////////////////////
/**
* @private
* @param {!Object} obj
* @param {string} key
* @param {*=} val
* @param {!Object=} descriptor
* @param {string=} strongType
* @param {function=} setter
* @return {!Object}
*/
function _amendProp(obj, key, val, descriptor, strongType, setter) {
descriptor = descriptor || null;
descriptor = _getDescriptor(descriptor, !!strongType || !!setter);
strongType = _getStrongType(strongType);
descriptor = strongType || setter
? _setupDescriptorByKeyWithSetter(val, descriptor, strongType, setter)
: _isAccessor(descriptor)
? cloneObj(descriptor)
: _setupDescriptorByKey(val, descriptor);
return _ObjectDefineProperty(obj, key, descriptor);
}
/**
* @private
* @param {!Object} obj
* @param {!Object} props
* @param {*} val
* @param {!Object=} descriptor
* @param {string=} strongType
* @param {function=} setter
* @return {!Object}
*/
function _amendProps(obj, props, val, descriptor, strongType, setter) {
descriptor = descriptor || null;
descriptor = _getDescriptor(descriptor, !!strongType || !!setter);
strongType = _getStrongType(strongType);
props = _is.arr(props)
? strongType || setter
? _setupPropsByKeyWithSetter(props, val, descriptor, strongType, setter)
: _setupPropsByKey(props, val, descriptor)
: strongType || setter
? _setupPropsWithSetter(props, descriptor, strongType, setter)
: _setupProps(props, descriptor);
return _ObjectDefineProperties(obj, props);
}
/**
* @private
* @param {!Object} obj
* @param {string} key
* @param {!Object} descriptor
* @return {!Object}
*/
function _amendConfig(obj, key, descriptor) {
return _ObjectDefineProperty(obj, key, descriptor);
}
/**
* @private
* @param {!Object} obj
* @param {!Object} props
* @return {!Object}
*/
function _amendConfigs(obj, props) {
return _ObjectDefineProperties(obj, props);
}
//////////////////////////////////////////////////////////
// PRIVATE METHODS - PROPERTIES SETUP
//////////////////////////////////////////////////////////
/**
* @private
* @param {!Object} props
* @param {!Object} descriptor
* @return {!Object}
*/
function _setupProps(props, descriptor) {
/** @type {!Object} */
var newProps;
/** @type {string} */
var key;
newProps = {};
for (key in props) {
if ( own(props, key) ) {
newProps[key] = _setupDescriptor(props[key], descriptor);
}
}
return newProps;
}
/**
* @private
* @param {!Object} props
* @param {!Object} descriptor
* @param {function} strongType
* @param {function} setter
* @return {!Object}
*/
function _setupPropsWithSetter(props, descriptor, strongType, setter) {
/** @type {!Object} */
var newProps;
/** @type {string} */
var key;
newProps = {};
for (key in props) {
if ( own(props, key) ) {
newProps[key] = _setupDescriptorWithSetter(props[key], descriptor, strongType, setter);
}
}
return newProps;
}
/**
* @private
* @param {!Array<string>} keys
* @param {*} val
* @param {!Object} descriptor
* @return {!Object}
*/
function _setupPropsByKey(keys, val, descriptor) {
/** @type {function} */
var setupDesc;
/** @type {!Object} */
var props;
/** @type {number} */
var len;
/** @type {number} */
var i;
setupDesc = _isAccessor(descriptor)
? function setupDesc(val, desc) { return cloneObj(desc); }
: _setupDescriptorByKey;
props = {};
len = keys.length;
i = -1;
while (++i < len) {
props[ keys[i] ] = setupDesc(val, descriptor);
}
return props;
}
/**
* @private
* @param {!Array<string>} keys
* @param {*} val
* @param {!Object} descriptor
* @param {function} strongType
* @param {function} setter
* @return {!Object}
*/
function _setupPropsByKeyWithSetter(keys, val, descriptor, strongType, setter) {
/** @type {!Object} */
var props;
/** @type {number} */
var len;
/** @type {number} */
var i;
props = {};
len = keys.length;
i = -1;
while (++i < len) {
props[ keys[i] ] = _setupDescriptorByKeyWithSetter(val, descriptor, strongType, setter);
}
return props;
}
/**
* @private
* @param {!Array} keys
* @param {!Object} desc
* @return {!Object}
*/
function _setupConfigs(keys, desc) {
/** @type {!Object} */
var props;
/** @type {number} */
var len;
/** @type {number} */
var i;
props = {};
len = keys.length;
i = -1;
while (++i < len) {
props[ keys[i] ] = desc;
}
return props;
}
//////////////////////////////////////////////////////////
// PRIVATE PROPERTIES - DESCRIPTORS SETUP
//////////////////////////////////////////////////////////
/**
* @private
* @type {string}
* @const
*/
var INVALID_STRONG_TYPE = 'Invalid type for object property value.';
/**
* @private
* @param {*} val
* @param {!Object} descriptor
* @return {!Object}
*/
function _setupDescriptor(val, descriptor) {
/** @type {!Object} */
var prop;
prop = cloneObj(descriptor);
val = _isDescriptor(val) ? val : { value: val };
return merge(prop, val);
}
/**
* @private
* @param {*} val
* @param {!Object} descriptor
* @param {function=} strongType
* @param {function=} setter
* @return {!Object}
*/
function _setupDescriptorWithSetter(val, descriptor, strongType, setter) {
/** @type {!Object} */
var prop;
prop = cloneObj(descriptor);
if ( _isDescriptor(val) ) {
prop = merge(prop, val);
if ( own(prop, 'writable') || _isAccessor(prop) ) return prop;
val = prop.value;
prop = _cloneAccessor(prop);
}
prop = _setupGetSet(val, prop, strongType, setter);
return prop;
}
/**
* @private
* @param {*} val
* @param {!Object} descriptor
* @return {!Object}
*/
function _setupDescriptorByKey(val, descriptor) {
/** @type {!Object} */
var prop;
prop = cloneObj(descriptor);
prop.value = val;
return prop;
}
/**
* @private
* @param {*} val
* @param {!Object} descriptor
* @param {function=} strongType
* @param {function=} setter
* @return {!Object}
*/
function _setupDescriptorByKeyWithSetter(val, descriptor, strongType, setter) {
/** @type {!Object} */
var prop;
prop = cloneObj(descriptor);
prop = _setupGetSet(val, prop, strongType, setter);
return prop;
}
/**
* @private
* @param {*} val
* @param {!Object} descriptor
* @param {function=} strongType
* @param {function=} setter
* @return {!Object}
*/
function _setupGetSet(val, descriptor, strongType, setter) {
/** @type {!Error} */
var error;
descriptor.get = function() { return val; };
descriptor.set = strongType && setter
? function(newVal) {
if ( !strongType(newVal) ) {
error = new TypeError(INVALID_STRONG_TYPE);
error.__setter = true;
error.__type = true;
throw error;
}
val = setter(newVal, val);
}
: strongType
? function(newVal) {
if ( !strongType(newVal) ) {
error = new TypeError(INVALID_STRONG_TYPE);
error.__setter = true;
error.__type = true;
throw error;
}
val = newVal;
}
: function(newVal) { val = setter(newVal, val); };
return descriptor;
}
//////////////////////////////////////////////////////////
// PRIVATE METHODS - DESCRIPTORS HELPERS
//////////////////////////////////////////////////////////
/**
* @private
* @type {!Object}
* @const
*/
var DATA_DESCRIPTOR = {
writable: true,
enumerable: true,
configurable: true
};
/**
* @private
* @type {!Object}
* @const
*/
var ACCESSOR_DESCRIPTOR = {
enumerable: true,
configurable: true
};
/**
* @private
* @type {!Object}
* @const
*/
var DESCRIPTOR_PROPS = {
get: true,
set: true,
value: true,
writable: true,
enumerable: true,
configurable: true
};
/**
* @private
* @param {!Object} obj
* @return {boolean}
*/
function _isDescriptor(obj) {
/** @type {string} */
var key;
if ( !_is.obj(obj) ) return false;
for (key in obj) {
if ( own(obj, key) && !own(DESCRIPTOR_PROPS, key) ) return false;
}
return true;
}
/**
* @private
* @param {Object} obj
* @return {boolean}
*/
function _isData(obj) {
return own(obj, 'value') || own(obj, 'writable');
}
/**
* @private
* @param {Object} obj
* @return {boolean}
*/
function _isAccessor(obj) {
return own(obj, 'get') || own(obj, 'set');
}
/**
* @private
* @param {Object} descriptor
* @param {boolean=} hasSetter
* @return {!Object}
*/
function _getDescriptor(descriptor, hasSetter) {
/** @type {!Object} */
var defaultDescriptor;
if ( hasSetter && _isData(descriptor) ) {
defaultDescriptor = {};
if ( _is.bool( descriptor.enumerable ) ) {
defaultDescriptor.enumerable = descriptor.enumerable;
}
if ( _is.bool( descriptor.configurable ) ) {
defaultDescriptor.configurable = descriptor.configurable;
}
descriptor = defaultDescriptor;
}
defaultDescriptor = hasSetter || _isAccessor(descriptor)
? ACCESSOR_DESCRIPTOR
: DATA_DESCRIPTOR;
defaultDescriptor = cloneObj(defaultDescriptor);
return merge(defaultDescriptor, descriptor);
}
/**
* @private
* @param {!Object} descriptor
* @return {!Object}
*/
function _cloneAccessor(descriptor) {
/** @type {!Object} */
var accessor;
/** @type {string} */
var key;
accessor = {};
for (key in descriptor) {
if ( own(descriptor, key) && key !== 'value' ) {
accessor[key] = descriptor[key];
}
}
return accessor;
}
/**
* @private
* @param {string=} strongType
* @return {(function|undefined)}
*/
function _getStrongType(strongType) {
return strongType && function strongTypeCheck(newVal) {
return is(strongType, newVal);
};
}
//////////////////////////////////////////////////////////
// PRIVATE METHODS - OBJECT.DEFINE_PROPERTIES POLYFILLS
//////////////////////////////////////////////////////////
/**
* @private
* @type {boolean}
* @const
*/
var HAS_DEFINE_PROPS = !!Object.defineProperties && (function () {
/** @type {!Object} */
var descriptor;
/** @type {!Object} */
var obj;
/** @type {string} */
var key;
obj = {};
descriptor = {
enumerable: false,
value: obj
};
try {
Object.defineProperty(obj, 'prop', descriptor);
for (key in obj) {
if (key === 'prop') return false;
}
}
catch (e) {
return false;
}
return obj.prop === obj;
})();
/**
* @private
* @param {!Object} obj
* @param {string} key
* @param {!Object} descriptor
* @return {!Object}
*/
var _ObjectDefineProperty = HAS_DEFINE_PROPS
? Object.defineProperty
: function ObjectDefineProperty(obj, key, descriptor) {
obj[key] = own(descriptor, 'get') ? descriptor.get() : descriptor.value;
return obj;
};
/**
* @private
* @param {!Object} obj
* @param {!Object} props
* @return {!Object}
*/
var _ObjectDefineProperties = HAS_DEFINE_PROPS
? Object.defineProperties
: function ObjectDefineProperties(obj, props) {
/** @type {!Object} */
var prop;
/** @type {string} */
var key;
for (key in props) {
if ( own(props, key) ) {
prop = props[key];
obj[key] = own(prop, 'get') ? prop.get() : prop.value;
}
}
return obj;
};
//////////////////////////////////////////////////////////
// PRIVATE METHODS - GENERAL
//////////////////////////////////////////////////////////
/**
* @private
* @param {!Object} source
* @param {!Object} obj
* @return {boolean}
*/
function _hasKeys(source, obj) {
/** @type {string} */
var key;
for (key in obj) {
if ( own(obj, key) && !own(source, key) ) return false;
}
return true;
}
/**
* @private
* @type {!ErrorAid}
*/
var _error = newErrorMaker('amend');
//////////////////////////////////////////////////////////
// END OF PRIVATE SCOPE FOR AMEND
return amend;
})();
module.exports = amend;