// Licensed Materials - Property of IBM
//
// IBM Watson Analytics
//
// (C) Copyright IBM Corp. 2015, 2018
//
// US Government Users Restricted Rights - Use, duplication or
// disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
( function( exports, Object )
{
"use strict";
/*global Symbol*/
var hasOwnProperty = Object.prototype.hasOwnProperty;
var toString = Object.prototype.toString;
// RegExp set up to match BareJS and polyfill.io symbol strings
// polyfill uses "__\x01symbol:" and "__\x01symbol@@"
var reSymbol = /^__\d*\x01?[sS]ymbol/;
// By default, make members whose name does not start with _ or $ enumerable.
var reEnumerable = /^[^_\$]/;
var strUndef = "undefined";
var NativeSymbol = typeof Symbol !== strUndef ? Symbol : null;
//jshint -W122
var symIt = NativeSymbol && ( typeof Symbol.iterator === "symbol" ) ? Symbol.iterator : /*istanbul ignore next*/ null;
//jshint +W122
/**
* Polyfills for {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object Object}.
* Module that provides implementations for methods missing on Object. Methods that cannot be polyfilled close enough to
* the spec (since they rely on Native implementations) are not added to the Object global.
* @class module:barejs/polyfill.Object
*/
/** @lends module:barejs/polyfill.Object */
var stat = {};
/**
* Shortcut method that only defines a property if it is not already known
* @param {object} _target The object to polyfill
* @param {object} _members The members to polyfill
* @param {object} [_copy] Optional: an object that the definitions will be copied to.
* @param {string} [_ownerName] Optional: name of the owner object
* @memberof module:barejs/polyfill.Object~
* @private
*/
function polyMixin( _target, _members, _copy, _ownerName )
{
for ( var name in _members )
{
/*istanbul ignore else: we're working on clean objects, iterating prototype properties is unexpected*/
if ( _members.hasOwnProperty( name ) )
{
var member = _members[name], isFn = typeof member === "function";
if ( isFn && _ownerName )
member.displayName = _ownerName + "." + name;
if ( _copy )
_copy[name] = member;
if ( !( name in _target ) )
exports.defineProperty( _target, name, { enumerable : false, configurable: isFn, writable: isFn, value: member } );
}
}
}
/**
* Helper method that allows to easily apply static and prototype properties to a native object
* @param {function} _native The native Object constructor to polyfill
* @param {object} _static The static methods to polyfill. Can be null.
* @param {object} _proto The instance members to polyfill. Can be null.
* @param {object} [_copy] Optional: an object that the definitions will be copied to.
* @param {string} [_ownerName] Optional: the name of the owner object.
* Allows to add functions to "exports" as well, for unit testing.
* @memberof module:barejs/polyfill.Object
* @private
*/
exports.polyfill = function polyfill( _native, _static, _proto, _copy, _ownerName )
{
if ( _static )
polyMixin( _native, _static, _copy, _ownerName );
if ( _proto )
polyMixin( _native.prototype, _proto, _copy, _ownerName && ( _ownerName + ".prototype" ) );
return _native;
};
exports.shouldBeEnumerable = function shouldBeEnumerable( _name )
{
return typeof _name === "string" && reEnumerable.test( _name );
};
/**
* Utility method to check if _target is an Object
* @param _arg The argument to check.
* @returns {boolean} True if the target is an object, false otherwise
*/
function isObject( _arg )
{
switch ( _arg && typeof _arg )
{
case "object":
case "function":
return true;
default:
return false;
}
}
exports.isObject = isObject;
/**
* Utility method to convert target to an Object (according to Ecmascript standard)
* @param _arg The argument to check.
* @param _caller The function requesting the cast. If provided, changes the exception message.
* @returns {object} The argument, as object
* @throws {TypeError} A TypeError if _arg is null or undefined.
*/
function toObject( _arg, _caller )
{
switch ( _arg === null ? strUndef : typeof _arg )
{
case "undefined":
throw new TypeError( _caller ? _caller.displayName + " called on null or undefined" : "Cannot convert undefined or null to object" );
case "object":
case "function":
return _arg;
default:
return Object( _arg );
}
}
exports.toObject = toObject;
/**
* Check if _arg is callable (i.e. a function).
* @param _arg The argument to check.
* @returns {boolean} True if _arg is a function, false otherwise.
* @memberof module:barejs/polyfill.Object
* @private
*/
exports.isCallable = function isCallable( _arg )
{
// We can't check the internal [[Call]] property, so we rely on type checking.
return ( typeof _arg === "function" ) || ( toString.call( _arg ) === "[object Function]" );
};
/**
* Convenience method to check if _arg is callable (i.e. a function).
* Note: If a second argument is provided, that is returned instead of _arg.
* This allows inlining the ensureCallable method in convenient locations.
* @param _arg function to check
* @returns _arg, or second argument if present
* @throws {TypeError} if _arg is not callable.
* @memberof module:barejs/polyfill.Object
* @private
*/
exports.ensureCallable = function ensureCallable( _arg )
{
if ( !exports.isCallable( _arg ) )
throw new TypeError( _arg + " is not a function" );
return arguments.length > 1 ? arguments[1] : _arg;
};
/**
* Helper function that will attempt to set the ES6 iterator Symbol for a class.
* @param {object} _target The object to define the iterator on.
* @param {function} _function The function that will result in the iterator.
* @returns {object} `_target`.
* @memberof module:barejs/polyfill.Object
* @private
*/
function setIterator( _target, _function )
{
var def = { configurable: true, value: _function };
/*istanbul ignore else: always true in NodeJS*/
if ( symIt )
exports.defineProperty( _target, symIt, def );
// Set @@iterator for compliancy with polyfill libraries like core.js
exports.defineProperty( _target, "@@iterator", def );
return _target;
}
exports.setIterator = setIterator;
/**
* Helper function that will get the ES6 iterator Symbol for a class.
* @param {function} _class The constructor function to define the iterator on
* @returns {object} The iterator, or null.
* @memberof module:barejs/polyfill.Object
* @private
*/
function getIterator( _target )
{
var result = null;
if ( _target )
{
var obj = Object( _target );
if ( symIt && ( symIt in obj ) )
result = obj[symIt]();
else if ( "@@iterator" in obj )
result = obj["@@iterator"]();
}
return result;
}
exports.getIterator = getIterator;
////////////////////////////////////////////////////////////////////////////////////////////////////
// Grab some methods that we may have to provide fallbacks for
////////////////////////////////////////////////////////////////////////////////////////////////////
var modernPropertySupport = !!Object.defineProperties;
var legacyPropertySupport = ( ( "__defineGetter__" in Object.prototype ) && ( "__defineSetter__" in Object.prototype ) );
/*istanbul ignore next: We know we have Object.defineProperties in NodeJS*/
exports.propertyGetSetSupport = modernPropertySupport || legacyPropertySupport;
// Take care not to grab IE8's defineProperty that only works on DOM elements.
/*istanbul ignore else: native in NodeJS*/
if ( modernPropertySupport )
{
exports.defineProperty = Object.defineProperty;
exports.defineProperties = Object.defineProperties;
exports.getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
exports.getOwnPropertyDescriptors = Object.getOwnPropertyDescriptors;
}
exports.getPrototypeOf = Object.getPrototypeOf;
exports.freeze = Object.freeze;
exports.isFrozen = Object.isFrozen;
exports.seal = Object.seal;
exports.isSealed = Object.isSealed;
// ES6
exports.getOwnPropertyNames = Object.getOwnPropertyNames;
exports.getOwnPropertySymbols = Object.getOwnPropertySymbols;
/*istanbul ignore else: The tests are run with __ES__ set to 3*/
if ( __ES__ < 5 )
{
////////////////////////////////////////////////////////////////////////////////////////////////
// ES5 fallback functions
////////////////////////////////////////////////////////////////////////////////////////////////
// The following methods are not actually polyfills; these methods cannot be polyfilled.
// However, if the fallback behavior provided by the methods is sufficient, these can be used.
/*istanbul ignore if: native in NodeJS*/
if ( !exports.defineProperty )
{
/*
* Object.defineProperty cannot be emulated on browsers that do not support it.
* However, if the intention is to just set a value (no getters/setters), and the loss of
* enumerable, writable and configurable flags is acceptable, this method can be used.
* Uses the native method where possible
*
* Note: check for compliance via Object.defineProperties, since IE8 has an Object.defineProperty,
* but that only works on DOM elements.
*/
exports.defineProperty = function defineProperty( _object, _name, _definition )
{
if ( !isObject( _object ) )
throw new TypeError( "Object.defineProperty called on non-object" );
/*
* Fallback to simple assignment or __define[GS]etter__
*/
// Only assign if it actually exists.
if ( "value" in _definition )
{
_object[_name] = _definition.value;
}
else if ( ( "get" in _definition ) || ( "set" in _definition ) )
{
if ( !exports.propertyGetSetSupport )
throw new Error( "Property getters and setters are not supported in this environment" );
if ( "get" in _definition )
_object.__defineGetter__( _name, _definition.get );
if ( "set" in _definition )
_object.__defineSetter__( _name, _definition.set );
}
return _object;
};
}
/*istanbul ignore if: native in NodeJS*/
if ( !exports.defineProperties )
{
/*
* Uses the possibly emulated defineProperty and behaves like Object.defineProperties.
* Can only be used to set values (no getters/setters) in environments that do not support getters/setters.
* Uses the native method where possible
*/
exports.defineProperties = function defineProperties( _object, _properties )
{
if ( !isObject( _object ) )
throw new TypeError( "Object.defineProperties called on non-object" );
_properties = toObject( _properties );
// Assume there is no Object.keys in an environment that requires this polyfill.
for ( var i in _properties )
if ( hasOwnProperty.call( _properties, i ) && ( !reSymbol.test( i ) ) ) // Ignore Symbols
exports.defineProperty( _object, i, _properties[i] );
return _object;
};
}
/*istanbul ignore if: native in NodeJS*/
if ( !exports.getPrototypeOf )
{
/**
* Object.getPrototypeOf cannot be fully emulated on browsers that do not support it.
* We attempt to find a __proto__ or constructor.prototype.
* Attempt to get an objects prototype, returns null on failure
* @param {object} _object The object to get the prototype of
* @returns {object} The prototype of _object
* @memberof module:barejs/polyfill.Object
* @private
*/
exports.getPrototypeOf = function getPrototypeOf( _object )
{
switch ( _object === null ? strUndef : typeof _object )
{
case "undefined":
throw new TypeError( "Cannot convert undefined or null to object" );
case "boolean":
return Boolean.prototype;
case "number":
return Number.prototype;
case "string":
return String.prototype;
case "function":
return Function.prototype;
// case "object", and any other host value
default:
// jshint -W103
if ( "__proto__" in _object )
return _object.__proto__;
// jshint +W103
// If the object has the constructor property, this is already a prototype
if ( !hasOwnProperty.call( _object, "constructor" ) )
return _object.constructor.prototype;
// See if a framework set a superclass property
else if ( _object.constructor.superclass )
return _object.constructor.superclass.prototype;
if ( Array.isArray( _object ) )
return Array.prototype;
return null;
}
};
}
/*istanbul ignore if: native in NodeJS*/
if ( !exports.freeze )
{
/*
* Object.freeze cannot be emulated. This method is a NOOP if Object.freeze is not supported.
*/
exports.freeze = function freeze( _o ){ return _o; };
}
/*istanbul ignore if: native in NodeJS*/
if ( !exports.isFrozen )
{
/*
* Object.isFrozen cannot be emulated. This method is a NOOP if Object.isFrozen is not supported.
*/
exports.isFrozen = function isFrozen( _o ){ return false; };
}
/*istanbul ignore if: native in NodeJS*/
if ( !exports.seal )
{
/*
* Object.seal cannot be emulated. This method is a NOOP if Object.seal is not supported.
*/
exports.seal = function seal( _o ){ return _o; };
}
/*istanbul ignore if: native in NodeJS*/
if ( !exports.isSealed )
{
/*
* Object.isSealed cannot be emulated. This method is a NOOP if Object.isSealed is not supported.
*/
exports.isSealed = function isSealed( _o ){ return false; };
}
////////////////////////////////////////////////////////////////////////////////////////////////
// ES5 polyfills
////////////////////////////////////////////////////////////////////////////////////////////////
//
// ES5 - Object
//
( function()
{
/*global document, ActiveXObject*/
var createEmpty;
// While we generally prefer named constructors, avoid it here since it adds no value,
// and may even be confusing when looking at the prototype chain.
var Anonymous = function(){};
//jshint -W103
/*istanbul ignore else: NodeJS supports the __proto__ property*/
if ( ( !( { __proto__: null } instanceof Object ) ) || ( typeof document === strUndef ) )
{
// We can use the deprecated __proto__ property to create an object with no prototype
createEmpty = function()
{
return { __proto__: null };
};
}
//jshint +W103
else
{
// We grab a foreign Object.prototype so any object created from it has instanceof Object return false,
// and we can safely delete all properties from it without breaking regular objects.
createEmpty = function()
{
var shouldUseActiveX = ( function()
{
try
{
return !!( document.domain && new ActiveXObject( "htmlfile" ) );
}
catch ( ex )
{
return false;
}
}() );
function Empty() {}
if ( shouldUseActiveX )
{
Empty.prototype = ( function( _xDoc )
{
_xDoc.write( "<script><\/script>" );
_xDoc.close();
var empty = _xDoc.parentWindow.Object.prototype;
_xDoc = null;
return empty;
}( new ActiveXObject( "htmlfile" ) ));
}
else
{
Empty.prototype = ( function( _parent, _iframe )
{
_iframe.style.display = "none";
_parent.appendChild( _iframe );
// jshint -W107
_iframe.src = "javascript:";
// jshint +W107
var empty = _iframe.contentWindow.Object.prototype;
_parent.removeChild( _iframe );
_iframe = null;
return empty;
}( document.body || document.documentElement, document.createElement( "iframe" ) ) );
}
// Now delete all existing definitions on our "empty" object to make it truly empty
( function( _e )
{
delete _e.constructor;
delete _e.hasOwnProperty;
delete _e.propertyIsEnumerable;
delete _e.isPrototypeOf;
delete _e.toLocaleString;
delete _e.toString;
delete _e.valueOf;
}( Empty.prototype ) );
// Shortcut createEmpty for future calls
createEmpty = function()
{
// This returns an object for which instanceof Object is false
return new Empty();
};
return createEmpty();
};
}
/**
* Create an instance of an object that has another object as its prototype
* @param {object} _proto The prototype of the newly created object, or null.
* @param {object} _properties
* @returns {object} A new object that has the input object as prototype.
*/
stat.create = function create( _proto, _properties )
{
var result;
// _proto has 3 valid values: null or an Object (a function is an Object too)
if ( _proto === null )
{
result = createEmpty();
}
else
{
if ( !isObject( _proto ) )
throw new TypeError( "Object prototype may only be an Object or null: " + _proto );
Anonymous.prototype = _proto;
result = new Anonymous();
Anonymous.prototype = null; // Reset prototype so we don't hold a reference to _proto
}
if ( typeof _properties !== strUndef )
exports.defineProperties( result, toObject( _properties ) );
return result;
};
}() );
( function()
{
var hasDontEnumBug = !( { toString: null } ).propertyIsEnumerable( "toString" ),
dontEnums = [
"toString",
"toLocaleString",
"valueOf",
"hasOwnProperty",
"isPrototypeOf",
"propertyIsEnumerable",
"constructor"
],
dontEnumsLength = dontEnums.length;
/**
* Return the property names defined directly on object
* @param {object} _obj The target object.
* @returns {Array} String[] property names.
*/
stat.keys = function keys( _obj )
{
// Ensure object
_obj = toObject( _obj );
var result = [];
for ( var prop in _obj )
if ( hasOwnProperty.call( _obj, prop ) && ( !reSymbol.test( prop ) ) ) // Ignore Symbols
result.push(prop);
/*istanbul ignore if: not applicable in NodeJS*/
if ( hasDontEnumBug )
{
for ( var i = 0; i < dontEnumsLength; ++i )
if ( hasOwnProperty.call( _obj, dontEnums[i] ) )
result.push( dontEnums[i] );
}
return result;
};
}() );
}
/*istanbul ignore else: The tests are run with __ES__ set to 3*/
if ( __ES__ < 6 )
{
// Technically most of the methods set on exports are in ES5, but BareJS relies on them so ensure there's a fallback
/*istanbul ignore if: native in NodeJS*/
if ( !exports.getOwnPropertyNames )
{
exports.getOwnPropertyNames = function( _object )
{
var result = [];
if ( _object )
{
var obj = Object( _object );
for ( var key in obj )
{
if ( hasOwnProperty.call( obj, key ) && typeof key === "string" )
result.push( key );
}
}
return result;
};
}
/*istanbul ignore if: native in NodeJS*/
if ( !exports.getOwnPropertySymbols )
{
exports.getOwnPropertySymbols = function getOwnPropertySymbols( _target )
{
// Ensure object
_target = toObject( _target );
var result = [];
for ( var prop in _target )
if ( hasOwnProperty.call( _target, prop ) && ( reSymbol.test( prop ) ) )
result.push(prop);
return result;
};
}
/*istanbul ignore if: native in NodeJS*/
if ( !exports.getOwnPropertyDescriptor )
{
exports.getOwnPropertyDescriptor = function getOwnPropertyDescriptor( _object, _key )
{
var descriptor;
if ( _object )
{
var obj = Object( _object );
if ( hasOwnProperty.call( obj, _key ) )
{
descriptor = { configurable: true, enumerable: true };
var getter;
var setter;
if ( legacyPropertySupport )
{
getter = obj.__lookupGetter__( _key );
setter = obj.__lookupSetter__( _key );
}
if ( getter || setter )
{
if ( getter )
descriptor.get = getter;
if ( setter )
descriptor.set = setter;
}
else
{
descriptor.value = obj[_key];
}
}
}
return descriptor;
};
}
/*istanbul ignore if: native in NodeJS*/
if ( !exports.getOwnPropertyDescriptors )
{
exports.getOwnPropertyDescriptors = function( _object )
{
var descriptors = {};
if ( _object )
{
var names = exports.getOwnPropertyNames( _object );
for ( var i = 0, len = names.length; i < len; ++i )
descriptors[names[i]] = exports.getOwnPropertyDescriptor( _object, names[i] );
}
return descriptors;
};
}
/**
* Object.is() determines whether two values are the same value. Two values are the same if one of the following holds:
* - both undefined
* - both null
* - both true or both false
* - both strings of the same length with the same characters
* - both the same object
* - both numbers and
* - both +0
* - both -0
* - both NaN
* - or both non-zero and both not NaN and both have the same value
* @param _v1 The first value to compare.
* @param _v2 The second value to compare.
* @returns {boolean} A new object that has the input object as prototype.
*/
stat.is = function is( _v1, _v2 )
{
if ( _v1 === _v2 )
return ( _v1 !== 0 ) || ( 1 / _v1 === 1 / _v2 ); // Ensure Object.is( +0, -0 ) returns false
else
return ( _v1 !== _v1 ) && ( _v2 !== _v2 ); // Ensure Object.is( NaN, NaN ) returns true
};
/**
* The Object.assign() method only copies enumerable and own properties from a source object to a target object.
* It uses [[Get]] on the source and [[Put]] on the target, so it will invoke getters and setters.
* Therefore it assigns properties versus just copying or defining new properties.
* This may make it unsuitable for merging new properties into a prototype if the merge sources contain getters.
* For copying property definitions, including their enumerability, into prototypes Object.getOwnPropertyDescriptor() and Object.defineProperty() should be used instead.
* @param {object} _target The target to assign to.
* @param {object} _firstSource The first source object to copy from.
* @returns {object} the _target, with properties assigned.
*/
stat.assign = function assign( _target, _firstSource /*assign.length should be 2*/ )
{
// Ensure object
_target = toObject( _target );
for ( var arg = 1, argLen = arguments.length, source; arg < argLen; ++arg )
{
if ( isObject( source = arguments[arg] ) )
{
for ( var key in source )
{
/*istanbul ignore else: clean prototypes assumed*/
if ( hasOwnProperty.call( source, key ) )
_target[key] = source[key];
}
}
}
return _target;
};
// End of ES6 polyfill scope
}
if ( __ES__ < 7 )
{
/**
* The Object.values() method returns an array of a given object's own enumerable property values,
* in the same order as that provided by a for...in loop
* (the difference being that a for-in loop enumerates properties in the prototype chain as well).
* @param {object} _target The object to enumerate.
* @returns {Array} The array of values
*/
stat.values = function values( _target )
{
// Avoid using Array.map for speed (and perform in-place replacement)
for ( var t = toObject( _target ), result = Object.keys( t ), i = 0, len = result.length; i < len; ++i )
result[i] = t[result[i]];
return result;
};
/**
* The Object.entries() method returns an array of a given object's own enumerable property [key, value] pairs,
* in the same order as that provided by a for...in loop
* (the difference being that a for-in loop enumerates properties in the prototype chain as well).
* @param {object} _target The object to enumerate.
* @returns {Array} The array of values
*/
stat.entries = function entries( _target )
{
// Avoid using Array.map for speed (and perform in-place replacement)
for ( var t = toObject( _target ), result = Object.keys( t ), i = 0, len = result.length; i < len; ++i )
result[i] = [ result[i], t[result[i]] ];
return result;
};
// End of ES7 polyfill scope
}
// Apply static members (not using exports.polyfill since we only have static members)
polyMixin( Object, stat, exports, "Object" );
//
// ES6 - ES5 Patching
//
/*istanbul ignore else: The tests are run with __ES__ set to 3*/
if ( __ES__ < 6 )
{
// It is possible Object.create exists (natively or polyfilled), but does not support the second
// argument. In this case, we replace it with a method that will call defineProperties
// We define this in the ES6 scope since we assume ES7 browsers will all support the optional second argument.
/*istanbul ignore if: NodeJS's Object.create supports the second argument*/
if ( Object.create( null, { test: { value: true } } ).test !== true )
{
Object.create = ( function( _originalCreate )
{
/**
* Object.create wrapper that adds support for an optional second argument.
*/
return function create( _proto, _properties )
{
var result = _originalCreate.call( Object, _proto ); // Call native Object.create
if ( _properties )
exports.defineProperties( result, _properties );
return result;
};
}( Object.create ) );
}
}
// End of module
}( exports, Object ) );