var reduce = require('./reduce'); /** * Alternative to <var>Object.defineProperty</var> with more enhancements. * * <br> * <aside class='note'> * <h3>A few things to consider (see examples):</h3> * <ul> * <li>If <var>object</var> contains invalid {@link propertyDescriptor|property descriptor attributes}, * the value WON'T be used as a property descriptor.</li> * <li>Empty objects will be considered values.</li> * </ul> * </aside> * * @namespace * @memberof just * @throws <var>Object.defineProperty</var> exceptions. * @param {!object} object - The target. * @param {string} key - Key for the property. * @param {!object} [value={'value': value}] - A {@link propertyDescriptor|property descriptor} or some value. * @example <caption>Define a property using a value.</caption> * just.defineProperty({}, 'a', 1); // Same as Object.defineProperty({}, 'a', {'value': 1}) * * @example <caption>Define a property using a {@link propertyDescriptor|property descriptor}.</caption> * just.defineProperty({}, 'a', {'writable': true}); // Same as Object.defineProperty({}, 'a', {'writable': true}) * * @example <caption>Define a property with an empty object.</caption> * just.defineProperty({}, 'a', {}); // Same as Object.defineProperty({}, 'a', {'value': {}}); * * @return <var>object</var>. */ function defineProperty (object, key, value) { var descriptor = Object(value); var defaultDescriptors = ['value', 'writable', 'get', 'set', 'configurable', 'enumerable']; var descriptorKeys = reduce(descriptor, function (keys, value, key) { return keys.concat(key); }, []); var isEmptyObject = !descriptorKeys.length; var notADescriptor = isEmptyObject || descriptorKeys.some( function notInDescriptors (key) { return this.indexOf(key) === -1; }, defaultDescriptors ); if (notADescriptor) { descriptor = { 'value': value }; } Object.defineProperty(object, key, descriptor); return object; } module.exports = defineProperty;