/*! * @name @waca/barejs * @version 1.1.20181003 * @license * Licenced Materials - Property of IBM * * (C) Copyright IBM Corp. 2016, 2018 * * US Government Users Restricted Rights - Use, duplication or * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ (function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define("barejs", [], factory); else if(typeof exports === 'object') exports["barejs"] = factory(); else root["barejs"] = factory(); })(this, function() { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) /******/ return installedModules[moduleId].exports; /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ exports: {}, /******/ id: moduleId, /******/ loaded: false /******/ }; /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ // Flag the module as loaded /******/ module.loaded = true; /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ // Load entry module and return exports /******/ return __webpack_require__(0); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports, __webpack_require__) { __webpack_require__(1); __webpack_require__(13); __webpack_require__(16); module.exports = __webpack_require__(18); /***/ }), /* 1 */ /***/ (function(module, exports, __webpack_require__) { // 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( Object, Array, String, Error, TypeError, ObjectPolyfill, Map, Set, Symbol, WeakMap ) { "use strict"; /*global console, setTimeout*/ /*jshint latedef:false*/ /** * Note: decl is not a constructor; call its static members. * @class module:barejs.decl * @abstract * @classdesc Module for declaring classes, interfaces, enums, and checking implementations. * decl uses the inheritance natively supported by JavaScript, instead of trying to emulate * multiple inheritance or providing "super" or "base" keyword emulation. This combined with the * fact that decl doesn't generate a constructor function (the defining code has to supply it) * leads to classes with no run-time overhead. It also means there is no "magic" performed. * Implementors using decl's inheritance are responsible for calling the base class * constructor and methods using the standard JavaScript call mechanism: * * function A( _name ) * { * this.name = _name; * } * * decl.declareClass( A, * { * toString: function() * { * return this.name; * } * } * * function B( _name, _age ) * { * // Invoke base class constructor on this object * A.call( this, _name ); * this.age = _age; * } * * decl.declareClass( B, A, * { * toString: function() * { * // Invoke A::toString() and append our age to it. * return A.prototype.toString.call( this ) + "; age " + this.age; * } * } ); * * In the debug version of barejs, decl adds a lot of metadata to provide a great debugging experience. * When defined with named constructors, objects created with decl will be highly discoverable and debuggable in browsers like Chrome. */ // List of classes that are not allowed to be casted to. var uncastable_types = new Set(); var uncastable_keys = new Map(); // Grab slice from an array var slice = Array.prototype.slice; var hasOwnProperty = Object.prototype.hasOwnProperty; var canWriteFnName = !!( Object.defineProperties && Object.getOwnPropertyDescriptor ); /*istanbul ignore else: NodeJS supports this*/ if ( canWriteFnName ) { canWriteFnName = Object.getOwnPropertyDescriptor( Function.prototype, "name" ); canWriteFnName = !canWriteFnName || canWriteFnName.configurable; } var reSymbolProto = /^(?:@@([a-zA-Z0-9_\$]+)|\[\[([a-zA-Z0-9_\$]+)\]\])$/; var reStaticIgnore = /^(?:constructor|prototype|name|interfaces|superclass|\$private)$/; var metaData = new WeakMap(); /** * Convenience property to ease defining a read only property on an Interface. * It as simply a shortcut for '{ allowGet: true, allowSet: false }': * * decl.declareInterface( function MyInterface() {}, * { * // The following two definitions have exactly the same effect: * myProperty: decl.readOnlyProperty, * myProperty: { allowGet: true, allowSet: false } * } ); * * @member {object} * @readonly * @memberof module:barejs.decl */ var readOnlyProperty = ObjectPolyfill.freeze( { allowGet: true, allowSet: false } ); var native_ctors = [ Object, Array, Function, Boolean, Number, Math, Date, String, RegExp, Symbol, Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError ]; // Detect a bunch more of optional native constructors, so our native_ctor array is complete //jshint -W117 /*istanbul ignore else*/ if ( typeof ArrayBuffer !== "undefined" ) native_ctors.push( ArrayBuffer ); /*istanbul ignore else*/ if ( typeof Float32Array !== "undefined" ) native_ctors.push( Float32Array ); /*istanbul ignore else*/ if ( typeof Float64Array !== "undefined" ) native_ctors.push( Float64Array ); /*istanbul ignore else*/ if ( typeof Promise !== "undefined" ) native_ctors.push( Promise ); /*istanbul ignore else*/ if ( typeof Proxy !== "undefined" ) native_ctors.push( Proxy ); /*istanbul ignore else*/ if ( typeof Uint8Array !== "undefined" ) native_ctors.push( Uint8Array ); /*istanbul ignore else*/ if ( typeof Uint8ClampedArray !== "undefined" ) native_ctors.push( Uint8ClampedArray ); /*istanbul ignore else*/ if ( typeof Uint16Array !== "undefined" ) native_ctors.push( Uint16Array ); /*istanbul ignore else*/ if ( typeof Uint32Array !== "undefined" ) native_ctors.push( Uint32Array ); //jshint +W117 /** * Convenience property to ease defining a read/write property on an Interface. * It as simply a shortcut for '{ allowGet: true, allowSet: true }': * * decl.declareInterface( function MyInterface() {}, * { * // The following two definitions have exactly the same effect: * myProperty: decl.readWriteProperty, * myProperty: { allowGet: true, allowSet: true } * } ); * * @member {object} * @readonly * @memberof module:barejs.decl */ var readWriteProperty = ObjectPolyfill.freeze( { allowGet: true, allowSet: true } ); /* * Enable validating interfaces are implemented in debug mode * Except for Rhino, since it can't handle it... */ /*istanbul ignore else: We always test in DEBUG*/ if ( !(false) && // Detect Rhino so we can ignore it !( typeof load === "function" && ( typeof Packages === "function" || typeof Packages === "object" ) ) ) { var validateQueue = []; /** * Validate a class implements all interface members. * @param {function} _class The class to validate. * @memberof module:barejs.decl~ * @private */ var validateInterfacesImplemented = function( _class ) { var errors = []; if ( _class && _class.interfaces ) { _class.interfaces.forEach( function( _interface, _idxInterface ) { var lines = []; for ( var members = InterfaceMetaData.get( _interface ).members, i = 0, len = members.length; i < len; ++i ) { var member = members[i]; var error = null; switch ( member.type ) { case "function": var def = member.interfaces[0].prototype[member.name]; var impl = _class.prototype[member.name]; if ( typeof impl !== "function" ) error = "Missing implementation for {def}"; else if ( ( impl.length !== def.length ) && ( impl.proxy !== true ) ) error = "Signature mismatch, {def} defines " + def.length + " arguments but implementation has " + impl.length; break; case "property": if ( !( member.name in _class.prototype ) ) error = "Missing prototype definition for {def}"; break; } if ( error !== null ) lines.push( error.replace( "{def}", String( member ) ) ); } if ( lines.length > 0 ) { errors.push( "[" + describe( _interface ) + " @ index " + _idxInterface + "]\r\n\t\t" + lines.join( "\r\n\t\t" ) ); } }, this ); } if ( errors.length > 0 ) throw new Error( describe( _class ) + " has the following errors:\r\n\t" + errors.join( "\r\n\t" ) ); }; /** * Callback function to validate interfaces * @memberof module:barejs.decl~ * @private */ var handleValidateQueue = function() { // reset timeout id delete validateQueue.timeout; /*istanbul ignore if: sanity check, this function should not be called/queued with an empty queue*/ if ( validateQueue.length < 1 ) return; // The code below will report errors by throwing an exception. Ensure the validateQueue is empty var queue = validateQueue; validateQueue = []; queue.forEach( function( _class ) { // For interfaces, just create the metadata; this will do basic validation if ( isInterface( _class ) ) InterfaceMetaData.get( _class ); else validateInterfacesImplemented( _class ); } ); }; } /** * Generic getter method * @param {string} _name The name of the property. * @returns The value of the property * @memberof module:barejs.decl~ * @private */ function _get( _name ) { /*jshint validthis:true*/ return this[_name]; } /** * Generic setter method. * @param {string} _name The name of the property. * @param _value The value to assign. * @returns The new value of the property * @memberof module:barejs.decl~ * @private */ function _set( _name, _value ) { /*jshint validthis:true*/ return ( this[_name] = _value ); } /** * Used during object prototype expansion to resolve a getter definition * @memberof module:barejs.decl~ * @private */ function resolvePropertyAccessor( _target ) { // It is possible the target is also a property definition. Resolve it if ( _target && ( typeof _target === "object" ) ) { if ( hasOwnProperty.call( _target, "value" ) ) return _target.value; else if ( hasOwnProperty.call( _target, "get" ) ) return _target.get; } return _target; } /** * Iterator function that will modify the context to have a defineProperty * definition instead of direct properties. If the value is already a property definition, it is left * untouched. Once the object has been parsed, it can then be given to Object.create. * @memberof module:barejs.decl~ * @private */ function toDefineProperty( _value, _name, _object, _lookup ) { var def; if ( _value && ( typeof _value === "object" ) ) { if ( hasOwnProperty.call( _value, "value" ) ) { def = _value; } // Guard against map values as they have else if ( hasOwnProperty.call( _value, "get" ) || hasOwnProperty.call( _value, "set" ) ) { def = _value; // If there is no property support, we silently ignore properties /*istanbul ignore if: NodeJS supports properties*/ if ( !ObjectPolyfill.propertyGetSetSupport ) return null; // If there is a getter or setter, see if we need to resolve it if ( typeof def.get === "string" ) { def.getterName = def.get; def.get = resolvePropertyAccessor( _object[def.get] || ( _lookup && _lookup[def.get] ) ); } if ( typeof def.set === "string" ) { def.setterName = def.set; def.set = resolvePropertyAccessor( _object[def.set] || ( _lookup && _lookup[def.set] ) ); } } } if ( !def ) { def = { // Make Symbols and string keys starting with "_" not enumerable by default enumerable: ObjectPolyfill.shouldBeEnumerable( _name ), writable: true, value: _value }; } return def; } /** * Same purpose as toDefineProperty, but specialised for interfaces, on which we expect only * functions or objects that define get/set access. Performs validation no other properties are present. * @memberof module:barejs.decl~ * @private */ function toDefinePropertyInterface( _value, _name ) { var ok = false; var allowGet, allowSet; switch ( _value && typeof _value ) { case "function": // Functions are always OK ok = true; break; case "object": // If the decl constants where used, there is no sense in validating them ok = ( _value === readOnlyProperty ) || ( _value === readWriteProperty ); // If not, validate the object given to us if ( !ok ) { allowGet = ( "allowGet" in _value ) && _value.allowGet; allowSet = ( "allowSet" in _value ) && _value.allowSet; // allowGet, if defined, should be a boolean if ( typeof allowGet !== "boolean" ) throw new TypeError( "allowGet value is not a boolean" ); // allowSet, if defined, should be a boolean if ( typeof allowSet !== "boolean" ) throw new TypeError( "allowSet value is not a boolean" ); ok = allowGet || allowSet; // at least one needs to be true. } break; } if ( !ok ) throw new TypeError( "Values on an interface prototype must be either a function or an object containing allowGet or allowSet boolean properties." ); return { enumerable: true, value: _value }; } /** * Convenience method that will add a displayName to _function if not present, by concatenating * _objectName and _propName with a '.', optionally appending _suffix after _propName. * @param {function} _function The function to add the displayName to. * @param {string} _objectName The name of the object, for example "MyClass.prototype" * @param {string} _propName The name of the property (the function is added as), for example "myMethod" * @param {string} [_suffix] Optional: part to append to the name, for example " [GET]" for a getter function * @memberof module:barejs.decl~ * @private */ function displayName( _function, _objectName, _propName, _suffix ) { if ( canWriteFnName && !hasOwnProperty.call( _function, "name" ) ) ObjectPolyfill.defineProperty( _function, "name", { configurable: true, value: _propName } ); if ( !( "displayName" in _function ) ) ObjectPolyfill.defineProperty( _function, "displayName", { configurable: true, value: _objectName + "." + _propName + ( _suffix || "" ) } ); } /** * Utility method that returns _def expanded to a defineProperties argument. * Arguments that are a property definition are left alone, other are expanded to be a property definition * @param {object} _def The object whose properties to expand. * @param {function} _callback Function to use for the expand operation. * @param {string} [_objName] Optional: the logical name of _def, e.g. "MyClass.prototype" * @returns {object} _def made suitable for Object.defineProperties (or second argument of Object.create). * @memberof module:barejs.decl~ * @private */ function expandDefineProperties( _def, _lookup, _callback, _objName ) { if ( _def ) { // Ensure object _def = Object( _def ); for ( var names = Object.keys( _def ), i = 0, len = names.length, name, prop, sym; i < len; ++i ) { name = names[i]; sym = reSymbolProto.exec( name ); if ( sym ) { //jshint -W122 // The regexp matches one of two possible forms ("@@symbolName" or "[[symbolName]]"), // which means the symbol name may be in either capture group sym = Symbol[ sym[1] || sym[2] ]; if ( typeof sym !== "symbol" ) { delete _def[name]; continue; } //jshint +W122 } prop = _callback( _def[name], sym || name, _def, _lookup ); if ( sym ) { delete _def[name]; _def[sym] = prop; } else if ( _def[name] !== prop ) { // on rare occasions we may need to drop a property, e.g. when there is no getter/setter support. if ( prop === null ) delete _def[name]; else _def[name] = prop; } if ( prop && _objName ) { if ( "value" in prop ) { if ( ObjectPolyfill.isCallable( prop.value ) ) displayName( prop.value, _objName, name ); } else { if ( prop.get && !prop.getterName ) displayName( prop.get, _objName, name, " [GET]" ); if ( prop.set && !prop.setterName ) displayName( prop.set, _objName, name, " [SET]" ); } } } } return _def; } /** * Tells the proxy system casting to this type is not allowed. Should only be used for very low * level classes, otherwise performance will be impacted. * @param {function} _class The type to disallow casting to * @returns {Symbol} Key to cast to this type. NEVER export this key in any way. * @memberof module:barejs.decl */ function preventCast( _class ){ if ( typeof _class !== "function" ) throw new TypeError( "_class must be a function" ); if ( uncastable_types.has( _class ) ) throw new Error( "Already declared uncastable" ); // Register uncastable, generate key and store it at the correct index // Symbol is meant to make a "private key", so it seems suitable enough to use as a key for preventCast. var key = Symbol( _class.name ); uncastable_types.add( _class ); uncastable_keys.set( key, _class ); return key; } // Allow decl to cast back without knowing the right type // NOTE: This value should never be exported var ObjectKey = preventCast( Object ); /** * Method that sets up inheritance. Doesn't perform any validation, this should be done beforehand. * @param {function} _class Class to set up the inheritance for * @param {function} _base The class to derive from. * @returns {function} Class, now deriving from _base * @memberof module:barejs.decl~ * @private */ function derive( _class, _base, _proto ) { // Apply prototype inheritance _class.prototype = Object.create( _base.prototype, _proto || undefined ); // Reset the constructor (non enumerable, but writable, just like browsers set it). ObjectPolyfill.defineProperty( _class.prototype, "constructor", { writable : true, value : _class } ); // Set superclass on constructor function // Note: decl methods should not rely too much on superclass being set, it's for convenience only return ObjectPolyfill.defineProperty( _class, "superclass", { value : _base } ); } // // Helper classes for metadata // /** * @classdesc Base class to gather information about a member of an interface. * @class module:barejs.decl~InterfaceMember * @param {function[]} _interfaces The interface(s) on which the method is defined. * @param {string} _name The name of the method on the interface. * @private */ function InterfaceMember( _interfaces, _name ) { this.interfaces = _interfaces; this.name = _name; } derive( InterfaceMember, Object, /** @lends module:barejs.decl~InterfaceMember */ { type: { value: "member" }, /** * Provides a string representation of the member, for example "member myFunction on interface IMyInterface". * @returns {string} The string representation of the member */ toString: { value: function toString() { return this.type + " \"" + String( this.name ) + "\" defined on " + this.interfaces.map( describe ).join( ", " ); } } } ); /** * @classdesc Stores information about a method on an interface. * @class module:barejs.decl~InterfaceMethod * @param {function} _interface The interface on which the method is defined. * @param {string} _name The name of the method on the interface. * @private */ function InterfaceMethod( _interface, _name ) { InterfaceMember.call( this, [_interface], _name ); } derive( InterfaceMethod, InterfaceMember, /** @lends module:barejs.decl~InterfaceMethod */ { type: { value: "function" } } ); /** * @classdesc Stores information about a property on an interface * @class module:barejs.decl~InterfaceProperty * @param {function[]} _interfaces The interfaces on which the property is defined. * @param {string} _name The name of the property on the interface. * @param {boolean} _allowGet Whether getting this property is allowed. * @param {boolean} _allowSet Whether setting this property is allowed. * @private */ function InterfaceProperty( _interfaces, _name, _allowGet, _allowSet ) { InterfaceMember.call( this, _interfaces, _name ); this.allowGet = _allowGet; this.allowSet = _allowSet; } derive( InterfaceProperty, InterfaceMember, /** @lends module:barejs.decl~InterfaceProperty */ { type: { value: "property" }, /** * Merge two definitions into a new InterfaceProperty. Used to resolve collisions between interfaces * @param {module:barejs.decl~InterfaceProperty} _otherProperty The property to merge with. * @returns {module:barejs.decl~InterfaceProperty} The merged InterfaceProperty. Might be the original, if the interfaces was already known. */ merge: { value: function( _otherProperty ) { if ( _otherProperty === this ) // sanity return this; // merge interfaces arrays for ( var interfaces = this.interfaces.slice( 0 ), i = 0, len = _otherProperty.interfaces.length, iface; i < len; ++i ) { if ( interfaces.indexOf( iface = _otherProperty.interfaces[i] ) ) interfaces.push( iface ); } return new InterfaceProperty( interfaces, this.name, this.allowGet || _otherProperty.allowGet, this.allowSet || _otherProperty.allowSet ); } } } ); /** * Stores metadata about members of this interface, members of base interfaces and the combined list. * This allows methods like hasInterface and proxy to quickly iterate over the list of members. * @class module:barejs.decl~InterfaceMetaData * @memberof module:barejs.decl~ * @private */ function InterfaceMetaData() { this.directMembers = []; this.inheritedMembers = []; this.members = null; } /** * merge directMembers and inheritedMembers into one */ InterfaceMetaData.prototype.merge = function() { var mergeMap; var i, len, member; if ( this.members ) return; if ( this.inheritedMembers.length < 1 ) { this.members = this.directMembers; } else if ( this.directMembers.length < 1 ) { this.members = this.inheritedMembers; } else { mergeMap = Object.create( null ); // Start by copying the directMembers this.members = this.directMembers.slice( 0 ); // Then iterate them to initialize the merge map for ( i = 0, len = this.members.length; i < len; ++i ) mergeMap[this.members[i].name] = true; // Next, iterate inherited members for ( i = 0, len = this.inheritedMembers.length; i < len; ++i ) { // No point in updating the merge map, this is the last iteration of the merge // Only add the member if it wasn't redefined if ( mergeMap[(member = this.inheritedMembers[i]).name] !== true ) this.members.push( member ); } this.members.sort( function( _a, _b ) { if ( _a.name === _b.name ) return 0; var ta = typeof _a.name; return ( ta === typeof _b.name ) && ( ta === "string" ) && ( _a.name > _b.name ) ? 1 : -1; } ); } }; /** * Build meta data for an interface, like the list of all methods required by the interface. */ InterfaceMetaData.get = function( _interface ) { if ( !isInterface( _interface ) ) throw new TypeError( "_interface is not an Interface" ); var meta = metaData.get( _interface ); if ( !meta ) { metaData.set( _interface, meta = new InterfaceMetaData() ); var mergeMap = Object.create( null ); // Merge inherited members if ( _interface.interfaces ) { _interface.interfaces.forEach( function( _extendedInterface ) { var members = InterfaceMetaData.get( _extendedInterface ).members, member, existing; for ( var i = 0, len = members.length; i < len; ++i ) { member = members[i]; if ( ( existing = mergeMap[member.name] ) && ( existing !== member ) ) { // See if we need to do property merge magic if ( ( existing.type === "property" ) && ( member.type === "property" ) ) { meta.inheritedMembers[meta.inheritedMembers.indexOf( existing )] = mergeMap[member.name] = existing.merge( member ); } else { // Report the conflict throw new Error( describe( _interface ) + " has a conflict in extended interfaces: The " + existing + " conflicts with " + member + "." ); } } else { mergeMap[member.name] = member; meta.inheritedMembers.push( member ); } } } ); } // Add direct members (freeze prototype too, to protect it from modification after metadata is built). for ( var names = Object.keys( ObjectPolyfill.freeze( _interface.prototype ) ).concat( ObjectPolyfill.getOwnPropertySymbols( _interface.prototype ) ), i = 0, len = names.length; i < len; ++i ) { var name = names[i], target = _interface.prototype[name]; // Protect proxy features from colliding with the interface. if ( ( name === "as" ) || ( name === "is" ) ) throw new Error( "The " + ( new InterfaceMember( [_interface], name ) ) + " uses the reserved name \"" + name + "\", which is not allowed." ); // Explicitly ignore the constructor property for Rhino if ( name === "constructor" ) continue; var member = null, existing = mergeMap[name]; // First, just create the metadata (not adding it) switch ( target && typeof target ) { case "function": member = new InterfaceMethod( _interface, name ); break; case "object": if ( ( "allowGet" in target ) || ( "allowSet" in target ) ) { member = new InterfaceProperty( [_interface], name, target.allowGet === true, target.allowSet === true ); if ( !( member.allowGet || member.allowSet ) ) throw new Error( "The " + member + " is invalid: it doesn't allow get or set." ); } break; } if ( !member ) { throw new Error( "The " + ( new InterfaceMember( [_interface], name ) ) + " is invalid: expected a function, " + "or an object with allowGet or allowSet property, but got " + ( typeof target ) + target + " instead." ); } // Override or report conflict if ( existing ) { // Interfaces are allowed to redefine properties with more access (i.e. readWrite over read). // They are not allowed to revoke access or redefine a property with similar access if ( ( member.type === "property" ) && ( existing.type === "property" ) ) { // Test if the interface is removing access if ( existing.allowGet && !member.allowGet ) throw new Error( "The " + member + " has a conflict with " + existing + ": it is removing get access." ); if ( existing.allowSet && !member.allowSet ) throw new Error( "The " + member + " has a conflict with " + existing + ": it is removing set access." ); if ( ( existing.allowGet === member.allowGet ) && ( existing.allowSet === member.allowSet ) ) throw new Error( "The " + member + " is redefining " + existing + " with equal get/set access (so it is obsolete)." ); } else { throw new Error( "The " + member + " conflicts with " + existing + "." ); } } meta.directMembers.push( member ); } meta.merge(); } return meta; }; /** * Stores metadata about names and values on an enum. * This allows for quick reverse lookup * @class module:barejs.decl~EnumMetaData * @private */ function EnumMetaData( _enum ) { this.names = ObjectPolyfill.freeze( Object.keys( _enum ) ); // Use _get to resolve the enum property value this.values = ObjectPolyfill.freeze( this.names.map( _get, _enum ) ); } /** * Perform a case insensitive name lookup for an enum * @param {module:barejs.decl~Enum} _enum The enum to look up the name for * @param {string} _name The name to match * @returns {string} the found name, or null if not found. */ EnumMetaData.prototype.ciName = function( _name ) { var nameLower = String( _name ).toLowerCase(); for ( var i = this.names.length - 1; i >= 0; --i ) { if ( nameLower === this.names[i].toLowerCase() ) return this.names[i]; } return null; }; /** * Retrieve metadata for an enum */ EnumMetaData.get = function( _enum ) { var meta = metaData.get( _enum.constructor ); if ( !meta ) metaData.set( _enum.constructor, meta = new EnumMetaData( _enum ) ); return meta; }; // // Helper classes // function NullObject() {} NullObject.prototype = null; /** * Internal class for decl, serving as a base class for {@link module:barejs.decl~Interface Interface} and {@link module:barejs.decl~Enum Enum}. * Does not have Object.prototype in its prototype chain, so objects deriving from SpecialType are not instanceof Object. * @class module:barejs.decl~SpecialType */ function SpecialType() {} derive( SpecialType, NullObject, /** @lends module:barejs.decl~SpecialType# */ { // JSHint complains hasOwnProperty is a really bad name, but we are simply "restoring" it on a special type. // jshint -W001 /** * A SpecialType is not instanceof Object, but does have the Object.prototype.hasOwnProperty method. * @function * @param {string} _name The name of the property to check * @returns {boolean} True if the object has a direct property with _name, false otherwise. */ hasOwnProperty: { value: hasOwnProperty } // jshint +W001 } ); /** * Base class for interfaces * @class module:barejs.decl~Interface * @extends module:barejs.decl~SpecialType */ function Interface() {} // Make Interface a "special type" (new Interface() instanceof Object === false) derive( Interface, SpecialType, /** @lends module:barejs.decl~Interface# */ { /** * toString for Interface. * @function * @returns {string} The string [interface InterfaceName], where InterfaceName is * the name of the interface constructor function, or "Interface" for anonymous interfaces. */ toString: { value: function toString() { return "[interface " + ( this.constructor.name || "Interface" ) + "]"; } } } ); /** * Base class for Enum types declared with {@link module:barejs.decl#declareEnum decl.declareEnum} * @class module:barejs.decl~Enum * @extends module:barejs.decl~SpecialType */ function Enum() {} // Make Enum a "special type" (new Enum() instanceof Object === false) derive( Enum, SpecialType, /** @lends module:barejs.decl~Enum# */ { // Allow subclasses to redefine these methods (so make them writable) /** * Enum method: get the name of the specified value. If multiple names lead to the same value, the * first found name is returned * @function * @param {string} _value The value for which to get the name * @returns The name of the value, or null if not found */ nameOf: { writable: true, value: function nameOf( _value ) { var meta = EnumMetaData.get( this ); return meta.names[meta.values.indexOf( _value )] || null; } }, /** * Enum method: get the value of the specified name * @function * @param {string} _name The name of the value to get * @param {boolean} [_caseInsensitive=false] Optional, set to true to perform a case insensitive search * @returns {object} The enum value, or null if it wasn't found. */ valueOf: { writable: true, value: function valueOf( _name, _caseInsensitive ) { // Case sensitive or insensitive, see if the name is defined. if ( this.hasOwnProperty( _name ) ) return this[_name]; // If we're not case insensitive, we're not going to find the value if ( _caseInsensitive !== true ) return null; // Do a case insensitive lookup _name = EnumMetaData.get( this ).ciName( _name ); // ciName will return null if the name didn't match any entry return _name && this[_name]; } }, /** * Enum method: check if the enum has the specified name * @function * @param {string} _name The name to check * @param {boolean} [_caseInsensitive=false] Optional, set to true to perform a case insensitive search * @returns {boolean} True if the enum has the name, false otherwise. */ hasName: { writable: true, value: function hasName( _name, _caseInsensitive ) { // Always check hasOwnProperty first, to avoid the array lookup of case insensitive. return this.hasOwnProperty( _name ) || ( ( _caseInsensitive === true ) && ( EnumMetaData.get( this ).ciName( _name ) !== null ) ); } }, /** * Check if the enum has the specified value * @function * @param {object} _value The enum value to check for * @returns {boolean} True if the enum has the value, false otherwise. */ hasValue: { writable: true, value: function hasValue( _value ) { return EnumMetaData.get( this ).values.indexOf( _value ) >= 0; } }, /** * Utility method to parse an enum value, for example from input parsed from JSON. * Takes the following steps: * * 1. if _value is an actual enum value, return _value. * 2. if _value is a name of enum, return the value of that name * 3. if _throw is true, throw a RangeError * 4. return null * * @function * @param _value The value to parse * @param {boolean} _caseInsensitive Whether name matching should be case insensitive. * Defaults to false, specify true for case insensitive. * @param {boolean} [_throw=false] Optional: set to true to perform strict validation. * @returns The parsed value, or null if the value didn't parse. */ parse: { writable: true, value: function parse( _value, _caseInsensitive, _throw ) { var enumMeta = EnumMetaData.get( this ); if ( enumMeta.values.indexOf( _value ) >= 0 ) return _value; // After this point, _value is considered to be a potential name var name = _value; // Perform case insensitive lookup if needed if ( !this.hasOwnProperty( name ) && ( _caseInsensitive === true ) ) name = EnumMetaData.get( this ).ciName( name ); if ( name && this.hasOwnProperty( name ) ) return this[name]; if ( _throw === true ) throw new RangeError( "Could not parse enum value " + _value ); return null; } }, /** * Get the names of an enum * @function * @returns {Array} The names of an enum */ names: { writable: true, value: function names() { return EnumMetaData.get( this ).names; } }, /** * Get the values of an enum * @function * @returns {Array} The values of an enum */ values: { writable: true, value: function values() { return EnumMetaData.get( this ).values; } }, /** * Iterate over all enum name/value pairs. Signature attempts to match Array.prototype.forEach. * @function * @param {function} _callback The callback, called with _value, _name, _enum * @param {object} [_thisArg] Optional: the scope to call the callback in. */ forEach: { writable: true, value: function forEach( _callback/*, _thisArg*/ ) { for ( var meta = EnumMetaData.get( this ), idx = 0, len = meta.names.length, thisArg = ( arguments[1] || null ) && Object( arguments[1] ); idx < len; ++idx ) _callback.call( thisArg, meta.values[idx], meta.names[idx], this ); } }, /** * toString for Enum. * @function * @returns {string} The string [enum EnumName], where EnumName is * the name of the enum constructor function, or "Enum" for anonymous enumerations. */ toString: { value: function toString() { return "[enum " + ( this.constructor.name || "Enum" ) + "]"; } } } ); // These methods are added to a declareClass prototype var classProtoExtension = { /** * To be executed in the context of an object. * Allow "casting" between interface proxies and the original object. * @param {function} _class The type (constructor function) to cast to. * @param {boolean} [_strict=false] Optional: set to true to avoid a duck-type check, and only check `decl` * metadata for interfaces implemented. * @returns {object} A proxy, the original object, or null if the "cast" could not be performed. */ as: { value : function as( _class, _strict ) { // jshint validthis:true // Give ObjectKey special treatment, making it a "master key", allowing to cast back objects // that are not even instanceof Object. if ( _class === ObjectKey ) return this; // _class is supposed to be either a constructor function or a proxy key if ( typeof _class !== "function" ) { // Allow casting back by key (Symbol, handed out by preventCast). var type = uncastable_keys.get( _class ); if ( type ) return this instanceof type ? this : null; throw new TypeError( "as requires _class to be a (constructor) function" ); } else if ( uncastable_types.has( _class ) ) { throw new Error( "as does not allow casting to this type, specify a more specific type" ); } // If we get here, _class is a function if ( isInterface( _class ) && hasInterface( this, _class, _strict ) ) return proxy( this, _class ); else if ( this instanceof _class ) return this; // Type change failed return null; } }, /** * To be executed in the context of an object. * Allow checking if an object adheres to a specific type, or equals an instance. * @param {function} _other (Type|Interface) to test for, OR {object} (Instance) to check equality against * @param {boolean} [_strict=false] Optional: if _other is an Interface, set to true to avoid a duck-type * check, and only check `decl` metadata for interfaces implemented. * If `_other` is not an Interface, this param is ignored. * @returns {boolean} True if this object adheres to the type, or equals the _other instance. False otherwise. */ is: { value: function is( _other, _strict ) { // jshint validthis:true if ( typeof _other === "function" ) return ( this instanceof _other ) || ( ( isInterface( _other ) && hasInterface( this, _other, _strict ) ) ); else if ( isProxy( _other ) ) return this === _other.as( ObjectKey ); else return this === _other; } } }; // // Helper methods // /** * Attempts to discover an object's base class. * @param {function} _class Class constructor function * @returns {function} The bas constructor, defaults to Object if the base cannot be determined. * @memberof module:barejs.decl~ * @private */ function getBase( _class ) { var proto = null; if ( typeof _class === "function" ) { proto = ObjectPolyfill.getPrototypeOf( _class.prototype ); proto = proto && proto.constructor ? proto.constructor : Object; } return proto; } /** * Get the type of _target. * This is typeof enhanced. * @param _target The thing to get the type of. * @memberof module:barejs.decl~ * @private */ function type( _target ) { var t = _target === null ? "null" : typeof _target; if ( t === "function" ) { if ( _target.prototype instanceof Interface ) t = "interface"; else if ( _target.prototype instanceof Enum ) t = "enum"; else if ( !( "prototype" in _target ) ) t = "native function"; else if ( "superclass" in _target ) t = "class"; } else if ( t === "object" ) { if ( Array.isArray( _target ) ) return "array"; else if ( _target instanceof Enum ) t = "enum"; else if ( _target instanceof Interface ) t = "proxy"; } return t; } /** * Helper method that tries to get the name of a class. * @param {function|Object} _target The object to get the name of * @returns {string} The name of target, or null * @memberof module:barejs.decl~ * @private */ function name( _target ) { if ( !_target ) return null; else if ( typeof _target === "function" ) return _target.name || null; else if ( _target.constructor ) return _target.constructor.name || null; return null; } /** * Helper method that tries to build a description of an object. It gets the right type description * using type, and tries to append the name to it. The name is only available in environments that * support the name property on functions, and of course the function must be named. * Example: describe( SampleClass ); * If SampleClass is a named function this might return "class SampleClass". * Otherwise, it will return "class (Anonymous)". * @param {function} _fn The function to describe. * @memberof module:barejs.decl~ * @private */ function describe( _target ) { var n = name( _target ); return n ? type( _target ) + " " + n : type( _target ); } /** * Check if the prototype object is clean (has no properties defined). * @param {function} _class The constructor function whose prototype object to check. * @param {string} [_requester] Optional: name of the function requesting the check * @memberof module:barejs.decl~ * @private */ function checkCleanPrototype( _class, _requester ) { var props = Object.keys( _class.prototype ), idx = props.indexOf( "constructor" ); if ( idx >= 0 ) props.splice( idx, 1 ); if ( props.length > 0 ) { throw new Error( ( _requester ? _requester + ": " : "" ) + describe( _class ) + " already has properties defined on the prototype: " + props.join( ", " ) ); } } /** * Port "static" functions over from the base class. * @param {function} _class The constructor function to update with base class static functions. * @param {function} _base The base constructor to copy static functions of. * @memberof module:barejs.decl~ * @private */ function applyStatic( _class, _base, _stat ) { if ( _base && ( native_ctors.indexOf( _base ) < 0 ) ) { var descriptors = ObjectPolyfill.getOwnPropertyDescriptors( _base ); var staticInherited; var keys = Object.keys( descriptors ); for ( var i = 0, len = keys.length; i < len; ++i ) { var key = keys[i]; // Ignore keys that match reStaticIgnore, if ( ( typeof key !== "string" || !reStaticIgnore.test( key ) ) && // or keys that are already on _class or _stat, ( !hasOwnProperty.call( _class, key ) && !( _stat && hasOwnProperty.call( _stat, key ) ) ) && // or keys that are explicitly ignored using a $private function !( _base.$private && _base.$private( key ) ) ) { var def = descriptors[key]; if ( "value" in def && typeof def.value !== "function" && def.writable && ObjectPolyfill.propertyGetSetSupport ) { // Upgrade def to a get/set proxy def = { configurable: def.configurable, enumerable: def.enumerable, "get": _get.bind( _base, key ), "set": _set.bind( _base, key ) }; } // Make sure the definition is always configurable, as we're "inheriting" def.configurable = true; if ( !staticInherited ) staticInherited = {}; staticInherited[key] = def; } } if ( staticInherited ) defineObject( _class, staticInherited ); } if ( _stat ) defineObject( _class, _stat ); } /** * Helper function that sets the interfaces for a class and validates they are actually interfaces. * This method does not perform any validation on _class or its state. * @param {function} _class The class constructor * @param {Array} _interfaces The list of interfaces. * @param {Array} _baseInterfaces The list of interfaces on the base class. * @memberof module:barejs.decl~ * @private */ function setInterfaces( _class, _interfaces, _baseInterfaces ) { var interfaces = ( _baseInterfaces && _baseInterfaces.slice( 0 ) ) || []; if ( _interfaces && _interfaces.length ) { // Validate the interfaces specified are indeed interfaces. for ( var idx = 0, len = _interfaces.length; idx < len; ++idx ) { // An interface should derive DIRECTLY from Interface. if ( getBase( _interfaces[idx] ) !== Interface ) throw new Error( "Interface " + idx + " is not a valid interface." ); if ( interfaces.indexOf( _interfaces[idx] ) < 0 ) interfaces.push( _interfaces[idx] ); else if ( !(false) && ( typeof console !== "undefined" ) ) console.info( describe( _class ) + " declares to implement " + describe( _interfaces[idx] ) + " also implemented by a base class." ); } } // Freeze the interfaces array for security ObjectPolyfill.defineProperty( _class, "interfaces", { value : ObjectPolyfill.freeze( interfaces ) } ); } /** * See if _interface matches _searchInterface. This includes looking at extended interfaces. * @param {function} _interface The interface to check * @param {function} _searchInterface The interface to look for in _interface's tree. * @returns {boolean} True if the interface matches, false otherwise */ function matchInterface( _interface, _searchInterface ) { if ( _interface === _searchInterface ) return true; if ( _interface.interfaces ) { for ( var idx = 0, len = _interface.interfaces.length; idx < len; ++idx ) { if ( matchInterface( _interface.interfaces[idx], _searchInterface ) ) return true; } } return false; } /** * Wrapper for {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is Object.is} that will "unproxy" values. * * // This returns false, Object.is sees two different objects: * Object.is( instance, instance.as( MyInterface ); * * // This returns true, decl will unproxy proxies. * decl.is( instance, instance.as( MyInterface ) ); * * @param _a Any value to check for equality * @param _b Any value to check for equality * @returns {boolean} True if the values are considered equal, false otherwise. * @memberof module:barejs.decl */ function is( _a, _b ) { return Object.is( isProxy( _a ) ? _a.as( ObjectKey ) : _a, isProxy( _b ) ? _b.as( ObjectKey ) : _b ); } /** * Check if the _target is an interface. * Only works with class constructors, since there should be no instance of an interface. * @param {function} _target The class constructor to test if it is an interface. * @returns {boolean} True if _target is an interface, false otherwise. * @memberof module:barejs.decl */ function isInterface( _target ) { return ( typeof _target === "function" ) && ( _target.prototype instanceof Interface ); } /** * Check if the _target is an enum. * Only works with instances, since enums should not expose their class constructor directly. * @param {object} _target The instance to test if it is an enum. * @returns {boolean} True if _target is an enum, false otherwise. * @memberof module:barejs.decl */ function isEnum( _target ) { // Enums should always be an instance return _target instanceof Enum; } /** * Check if the target is a proxy object. * @param {object} _target The object to check. * @returns {boolean} True if _target is a proxy object, false otherwise. * @memberof module:barejs.decl */ function isProxy( _target ) { // _target must be an object, instanceof Interface, having an "as" method directly on the object (the "is" method is not tested) return ( _target instanceof Interface ) && _target.hasOwnProperty( "as" ); } /** * Checks if _class has _base as a superclass. Also true if _class === _base. * Do not use this method to check if an Object is of a specific type, use the instanceof operator * for that instead. * @param {function} _class The function to check. * @param {function} _base The base class to check for. * @returns {boolean} True if the class has the base class, false otherwise. * @memberof module:barejs.decl */ function hasBase( _class, _base ) { if ( typeof _class !== "function" ) throw new TypeError( "_class is not a (constructor) function" ); if ( typeof _base !== "function" ) throw new TypeError( "_base is not a (constructor) function" ); return ( _class === _base ) || ( _class.prototype instanceof _base ); } /** * Create and return a proxy object for the target * @param {object} _target The object to proxy * @param {function} _interface The interface defining the members to proxy. * @returns {object} The proxy object (instanceof _interface). * @memberof module:barejs.decl */ function proxy( _target, _interface ) { if ( !isInterface( _interface ) ) throw new TypeError( describe( _interface ) + " is not a valid Interface" ); if ( !_target ) throw new Error( "Cannot proxy " + describe( _target ) + " as " + describe( _interface ) ); // Don't proxy a proxy, instead attempt to proxy on the source object if ( isProxy( _target ) ) return proxy( _target.as( ObjectKey ), _interface ); // Create the proxy object var props = { // Adding the constructor shows proxy objects named as the interface in the debugger // (provided the interface function is named) constructor: { value : _interface }, // Add the as and is methods to the proxy, read-only and not enumerated as: { value : classProtoExtension.as.value.bind( _target ) }, is: { value : classProtoExtension.is.value.bind( _target ) } }; for ( var members = InterfaceMetaData.get( _interface ).members, idx = 0, len = members.length, member, prop; idx < len; ++idx ) { switch ( ( member = members[idx] ).type ) { case "function": prop = _target[member.name]; if ( typeof prop !== "function" ) throw new Error( "as( " + describe( _interface ) + " ) expected " + member + " to be on " + describe( _target.constructor ) + ", but it is missing." ); // Make the function proxies read-only, enumerable props[member.name] = { value : prop.bind( _target ), enumerable : true }; break; case "property": if ( !( member.name in _target ) ) throw new Error( "as( " + describe( _interface ) + " ) expected " + member + " to be on " + describe( _target.constructor ) + ", but it is missing." ); if ( ObjectPolyfill.propertyGetSetSupport ) { prop = { enumerable: true }; if ( member.allowGet ) prop.get = _get.bind( _target, member.name ); if ( member.allowSet ) prop.set = _set.bind( _target, member.name ); // No point in checking for property support: we already checked that in the if above props[member.name] = prop; } else if ( typeof console !== undefined ) { console.warn( "interface proxy skipping " + member + ", since the environment doesn't support getters and setters." ); } break; } } // Attempt to seal the proxy; we don't need to freeze since no properties are configurable return ObjectPolyfill.seal( Object.create( _interface.prototype, props ) ); } /** * Duck-type check for compliance with an interface * @param {object} _target The object to validate * @param {function} _interface The interface to check for * @returns {boolean} True if the object seems to implement all members * @memberof module:barejs.decl~ * @private */ function duckHasInterface( _target, _interface ) { var valid = !!_target; if ( valid ) { // Ensure object _target = Object( _target ); for ( var m = InterfaceMetaData.get( _interface ).members, i = m.length - 1; valid && i >= 0; --i ) { switch( m[i].type ) { case "function": valid = typeof _target[m[i].name] === "function"; break; case "property": valid = m[i].name in _target; break; } } } return valid; } /** * Checks if _target (or a base class) implements the specified Interface. * Works on both instances and the class constructor. * @param {object|Function} _target The object or class constructor to check. * @param {function} _interface The interface to check for. If interface is not a valid interface, * this method always returns false. * @param {boolean} [_strict=false] Optional: set to true to avoid a duck-type check, and only check decl * metadata for interfaces implemented. * @returns {boolean} True if _target (or a base class) implements the interface, false otherwise. * @memberof module:barejs.decl */ function hasInterface( _target, _interface, _strict ) { if ( !isInterface( _interface ) ) throw new TypeError( "hasInterface: _interface must be an interface defined with decl.declareInterface, but is " + describe( _interface ) ); if ( !_target ) return false; // Detect proxies if ( isProxy( _target ) ) return hasInterface( _target.as( ObjectKey ), _interface, _strict ); var isFn = typeof _target === "function"; // Walk up the inheritance tree for ( var base = isFn ? _target : _target.constructor; base && ( base !== Object ) && ( base !== Interface ) && ( base !== Enum ); base = getBase( base ) ) { if ( base.interfaces && matchInterface( base, _interface ) ) return true; } // Resort to duck-type check return ( _strict !== true ) && duckHasInterface( isFn ? _target.prototype : _target, _interface ); } // // Start of Declare methods // /** * Helper method that unifies errors returned by declare* methods. * @param {string} _name The name of the function from which the error is triggered * @param {Array} _arguments or (arguments object) of arguments * @param {string} _message The custom part of the message * @returns {string} The error message * @memberof module:barejs.decl~ * @private */ function formatErrorMessage( _name, _arguments, _message ) { return _name + "( " + Array.prototype.map.call( _arguments, describe ).join( ", " ) + " ): " + _message; } /** * Helper method that will validate the _class argument passed to declare(Class|Interface|Enum). * Ensures consistent validation across methods. * @param {function} _class The _class argument as received by the declare method. * @param {string} _method The name of the method requesting the validation. * @param {Array} _arguments The arguments passed to the requesting method. * @memberof module:barejs.decl~ * @private */ function validateClassArg( _class, _method, _arguments ) { // Validation if ( !_class || ( typeof _class !== "function" ) ) throw new TypeError( formatErrorMessage( _method, _arguments, "_class is not a function." ) ); // Some special methods don't have a prototype, warn when these are passed to declareClass if ( !( "prototype" in _class ) ) throw new Error( formatErrorMessage( _method, _arguments, "_class doesn't have a prototype property; it is probably a built-in function." ) ); if ( ( "superclass" in _class ) || ( "interfaces" in _class ) ) throw new Error( formatErrorMessage( _method, _arguments, "The " + describe( _class ) + " is already declared, cannot perform " + _method + "." ) ); if ( native_ctors.indexOf( _class ) >= 0 ) throw new Error( formatErrorMessage( _method, _arguments, "Attempt to call " + _method + " on built-in type" + ( _class.name ? " " + _class.name + "." : "" ) ) ); // Note: this check can fail if the base prototype can not be detected. We still perform it as // a convenience for detecting errors, and hope the check for existing properties on the // prototype will catch the other cases. var base = getBase( _class ); if ( base && ( base !== Object ) ) throw new Error( formatErrorMessage( _method, _arguments, "_class already has a base " + describe( base ) + "." ) ); // Throw an error if anything has been defined on the original prototype checkCleanPrototype( _class, _method ); } /** * Helper method that will pop the last value of an array if it's not a function. * If the last argument is a function, or the array is empty, the _array is not modified and null is returned. * @param {Array} _array The array to pop the non-function from. * @memberof module:barejs.decl~ * @private */ function popNonFunction( _array ) { var len = _array.length; return ( len > 0 ) && ( typeof _array[len - 1] !== "function" ) ? Object( _array.pop() ) : null; } /** * Helper method that perform the actual class definition for both abstractClass and declareClass. * @param {String} _definingName The function that is requesting a class be made, e.g. abstractClass or declareClass. * @param {arguments} _args The arguments passed along to the declare function. * @param {Boolean} [_validate=false] Optional: whether interfaces should be validated for implementation. * @memberof module:barejs.decl~ * @private */ function makeClass( _definingName, _args, _validate ) { // normalize optional interfaces and/or prototype properties var cls = _args[0], base = null, interfaces = null, stat = null, proto = null; /*istanbul ignore else: We always test in DEBUG*/ if ( true ) validateClassArg( cls, _definingName, _args ); if ( _args.length > 1 ) { interfaces = slice.call( _args, 1, _args.length ); // If the first additional argument is null or a constructor function (not an interface), it is a base class. if ( ( interfaces[0] === null ) || ( ( typeof interfaces[0] === "function" ) && ( !isInterface( interfaces[0] ) ) ) ) base = interfaces.shift(); // If the last argument is not a function, assume it's a prototype definition. proto = popNonFunction( interfaces ); // If the second to last argument is not a function, assume it's a static definition. stat = popNonFunction( interfaces ); } /*istanbul ignore else: We always test in DEBUG*/ if ( true ) { // If a base class is passed, validate it too if ( base ) { if ( typeof base !== "function" ) { throw new TypeError( formatErrorMessage( _definingName, _args, "_base is not a function.\r\n" + "If you are passing a prototype definition, specify null as second argument." ) ); } if ( cls === base ) throw new Error( formatErrorMessage( _definingName, _args, "A class cannot extend itself." ) ); if ( !( "prototype" in base ) ) throw new Error( formatErrorMessage( _definingName, _args, "base doesn't have a prototype property; it is probably a built-in function." ) ); if ( hasBase( base, Enum ) ) throw new Error( formatErrorMessage( _definingName, _args, "Cannot extend an enum. To create an enum, use declareEnum." ) ); if ( hasBase( base, Interface ) ) { throw new Error( formatErrorMessage( _definingName, _args, "Cannot extend an interface.\r\n" + "To declare implementing interfaces, add them as arguments after _base; passing null as base class.\r\n" + "To create an interface extending another interface, use declareInterface instead." ) ); } } } if ( base === null ) base = Object; derive( cls, base, expandDefineProperties( proto, base && base.prototype, toDefineProperty, ( cls.name || "(Class)" ) + ".prototype" ) ); setInterfaces( cls, interfaces, base.interfaces ); // Apply static definition if ( base !== Object || stat ) applyStatic( cls, base, stat ); // If not inherited from a base class, add certain utility methods like "is" and "as" to the class. if ( !( "as" in cls.prototype ) ) ObjectPolyfill.defineProperties( cls.prototype, classProtoExtension ); // If we or our base have any interfaces, and if we're validating /*istanbul ignore else: We always test in DEBUG*/ if ( !(false) && _validate && ( cls.interfaces.length > 0 ) ) { // If we have a prototype definition ... if ( proto ) { // validate immediately. validateInterfacesImplemented( cls ); } else { // We can't validate immediately (since methods are expected to be added via // MyClass.prototype.method = function() {}; calls), so we queue validation. _validate.push( cls ); if ( !( "timeout" in _validate ) ) _validate.timeout = setTimeout( handleValidateQueue, 1 ); } } return cls; } /** * Declare a constructor function to be an abstract class. Allows specifying an optional base class and interfaces implemented. * When reading or writing decl.abstractClass statements, it might help to know it was designed to mimic popular languages * in its format. Here's an example: * * // With common languages * abstract class ClassName : BaseClass, Interface1, Interface2 // C# * abstract class ClassName extends BaseClass implements Interface1, Interface2 // Java * { * private String _name; * * public ClassName( _name ) * { * super( 42 ); * this._name = _name; * } * * public String toString() * { * return this._name; * } * } * * // With barejs.decl: * * function ClassName( _name ) * { * BaseClass.call( this, 42 ); * this._name = _name; * } * * decl.abstractClass( ClassName, BaseClass, Interface1, Interface2, * { * // This puts the _name property as null on the prototype, * // which is purely for clarity (e.g. stating it exists). * _name: null, * * toString: function() * { * return this._name; * } * } * * - If a base class is provided, decl will ensure _class.prototype is instanceof _base.prototype. * - For abstract classes, decl will not validate if interface methods are implemented. * - If a _static argument is specified, it will be applied to the constructor function using {@link module:barejs.decl.defineObject defineObject}. * - If a _prototype argument is specified, it will be applied to the prototype using {@link module:barejs.decl.defineObject defineObject}. * - If only 1 object is supplied, it is always interpreted as prototype definition, never as static. * You must specify null for the prototype object if you only want to specify static members. * * By default, any static members (except `name`, `prototype`, `constructor`, `superclass` and other metadata) will inherit. * A class can make static functions "private" by defining a static `$private` function, accepting a String/Symbol as key. * This function should return `true` for any keys that should *not* inherit. The `$private` function itself will never inherit. * * @param {function} _class The constructor function of the class * @param {function} [_base] Optional: Extended base class * @param {...function} [_interface] Optional: Any number of implemented interfaces * @param {object} [_static] Optional: static definition; properties that will be added to the constructor function. * @param {object} [_prototype] Optional: prototype definition: properties that will be added to the prototype * @returns {function} The constructor function (**_class**), so it can immediately be returned * @memberof module:barejs.decl */ function abstractClass( _class/*[, _base] [, _interface...] [, _static] [, _prototype] */ ) { return makeClass( "abstractClass", arguments ); } /** * Declare a constructor function to be a class. Allows specifying an optional base class and interfaces implemented. * When reading or writing decl.declareClass statements, it might help to know it was designed to mimic popular languages * in its format. Here's an example: * * // With common languages * class ClassName : BaseClass, Interface1, Interface2 // C# * class ClassName extends BaseClass implements Interface1, Interface2 // Java * { * private String _name; * * public ClassName( _name ) * { * super( 42 ); * this._name = _name; * } * * public String toString() * { * return this._name; * } * } * * // With barejs.decl: * * function ClassName( _name ) * { * BaseClass.call( this, 42 ); * this._name = _name; * } * * decl.declareClass( ClassName, BaseClass, Interface1, Interface2, * { * // This puts the _name property as null on the prototype, * // which is purely for clarity (e.g. stating it exists). * _name: null, * * toString: function() * { * return this._name; * } * } * * - If a base class is provided, decl will ensure _class.prototype is instanceof _base.prototype. * - If interfaces are declared, decl will validate methods are implemented. * - If a _static argument is specified, it will be applied to the constructor function using {@link module:barejs.decl.defineObject defineObject}. * - If a _prototype argument is specified, it will be applied to the prototype using {@link module:barejs.decl.defineObject defineObject}. * - If only 1 object is supplied, it is always interpreted as prototype definition, never as static. * You must specify null for the prototype object if you only want to specify static members. * * By default, any static members (except `name`, `prototype`, `constructor`, `superclass` and other metadata) will inherit. * A class can make static functions "private" by defining a static `$private` function, accepting a String/Symbol as key. * This function should return `true` for any keys that should *not* inherit. The `$private` function itself will never inherit. * * @param {function} _class The constructor function of the class * @param {function} [_base] Optional: Extended base class * @param {...function} [_interface] Optional: Any number of implemented interfaces * @param {object} [_static] Optional: static definition; properties that will be added to the constructor function. * @param {object} [_prototype] Optional: prototype definition: properties that will be added to the prototype * @returns {function} The constructor function (**_class**), so it can immediately be returned * @memberof module:barejs.decl */ function declareClass( _class/*[, _base] [, _interface...] [, _static] [, _prototype] */ ) { return makeClass( "declareClass", arguments, validateQueue ); } /** * Declare an interface. An interface can extend multiple interfaces by passing them as additional parameters. * The constructor function _class will be made to derive from the special internal {@link module:barejs.decl~Interface Interface} type. * It is not meant to be instantiated, and decl will never call the interface's constructor. * @param {function} _class The "constructor" function to declare as an interface. * @param {...function} [_interface] Any number of interfaces to extend. * @param {object} [_static] Optional: static definition; properties that will be added to the constructor function. * @param {object} [_prototype] Optional: prototype to apply * @returns {function} The interface definition (_class). * @memberof module:barejs.decl */ function declareInterface( _class /*[, _interface...] [, _static] [, _prototype] */ ) { var interfaces = null, stat = null, proto = null; // Development time validation /*istanbul ignore else: We always test in DEBUG*/ if ( true ) validateClassArg( _class, "declareInterface", arguments ); // If the interface extends other interfaces, set up the inheritance. if ( arguments.length > 1 ) { interfaces = slice.call( arguments, 1, arguments.length ); // If the last argument is not a function, assume it's a prototype definition. proto = popNonFunction( interfaces ); // If the second to last argument is not a function, assume it's a static definition. stat = popNonFunction( interfaces ); } // Each interface derives directly from Interface so it is easy to detect interfaces. derive( _class, Interface, expandDefineProperties( proto, Interface.prototype, toDefinePropertyInterface, _class.name || "(Interface)" ) ); setInterfaces( _class, interfaces, null ); if ( stat ) applyStatic( _class, null, stat ); // Development time validation /*istanbul ignore else: We always test in DEBUG*/ if ( !(false) && validateQueue ) { // If we don't have a prototype definition ... if ( proto === null ) { // We can't validate immediately (since methods are expected to be added via // MyInterface.prototype.method = function() {}; calls), so we queue validation. // Prepend interfaces so they get validated first validateQueue.unshift( _class ); if ( !( "timeout" in validateQueue ) ) validateQueue.timeout = setTimeout( handleValidateQueue, 1 ); } else { // Otherwise just validate immediately. // Creating the interface metadata will perform validation of the interface. InterfaceMetaData.get( _class ); } } return _class; } /** * Declare an enum. decl will make _class derive from the special internal {@link module:barejs.decl~Enum Enum} type, * and return a new instance of it. Enum values should be set on 'this' in the constructor, utility methods should be * added to the prototype. * * var SampleEnum = decl.declareEnum( function SampleEnum() * { * this.Bit1 = 1; * this.Bit2 = 2; * this.Bit3 = 4; * this.Bit4 = 8; * }, * // End of constructor, what follows is the prototype definition: * { * hasBit: function( _bit, _value ) * { * // hasValue is provided by the Enum base class * if ( !this.hasValue( _bit ) ) * throw new TypeError( "Unknown SampleEnum value: " + _bit ); * return _value & _bit === _bit * } * } ); * * // SampleEnum is now instanceof the SampleEnum function passed to decl. * SampleEnum.hasBit( SampleEnum.Bit2, 3 ); // true * // And it inherited decl's Enum type members * SampleEnum.names(); // ["Bit1", "Bit2", "Bit3", "Bit4"] * SampleEnum instanceof Object; // false * * Note that the prototype property, if specified, is applied using {@link module:barejs.decl.defineObject defineObject}. * @param {function} _class The "constructor" function to declare as an Enum. * @param {object} [_prototype] Optional: things to add to the enum prototype. * @returns {object} The enum instance (instanceof _class). * @memberof module:barejs.decl */ function declareEnum( _class/*[, _prototype]*/ ) { /*istanbul ignore else: We always test in DEBUG*/ if ( true ) validateClassArg( _class, "declareEnum", arguments ); // An enum inherits directly from Enum, so they can be easily detected (and receive some helper methods). derive( _class, Enum, expandDefineProperties( arguments[1], Enum.prototype, toDefineProperty, ( _class.name || "(Enum)" ) ) ); // jshint -W055 // Return an instance for an enum return ObjectPolyfill.freeze( new _class() ); // jshint +W055 } /** * defineObject is similar to {@link module:barejs.decl.defineProperties decl.defineProperties}, but it expands the _definition's properties if needed. * It will update values of properties that are not property assigment definitions to be proper property definitions, defaulting to: * * { configurable: false, writable: true, enumerable: true, value: <value> } * * (Note: enumerable will be `false` if the name starts with _ or is a Symbol). * defineObject will iterate the _definition object and expand properties on it. Please be aware of the following: * 1. **_destination** will be modified. If that's a problem, use {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign Object.assign} to create a copy first. * 2. Existing properties are scanned for presence of a **value**, **get** or **set** property. If these are present on a value, you **must** use the full property syntax: * * decl.defineObject( MyClass, * { * // Since the object we want to assign to the MyClass constructor function has properties that make it look like * // a property definition, we have to wrap it in a property definition as required by Object.defineProperties. * staticFlags: { enumerable: true, value: { get: true, set: false } } * } ); * * 3. defineObject will silently ignore getter/setter properties in environments that don't support them, unlike {@link module:barejs.decl.defineProperties}. * 4. You can reference a getter or setter by name, provided it is also on the definition object: * * decl.defineObject( {}, * { * // underlying data Array, not enumerable, configurable or writable * _values: { value: [] }, * // getSize function that returns the length of the _values * getSize: function() { return this._values.length; }, * // Size property. Refers to the getSize function for the getter, instead of using an inline function. * size: { enumerable: true, get: "getSize" } * } ); * * @param {object} _target The target object * @param {object} _definition The definitions to assign to _target. Note that _definition will be modified to contain property definitions(!). * @param {string} [_objectName] Optional: the name of the object. If passed, decl will generate displayName properties on methods for an enhanced debugging experience. * For example: if "decl" is passed as name, and there's an "is" function on _definition, the displayName of the "is" function will be set to "decl.is"). * @returns _target The target object, expanded * @memberof module:barejs.decl */ function defineObject( _target, _definition/*, _objectName*/ ) { if ( !_definition ) throw new Error( "Missing definition" ); return ObjectPolyfill.defineProperties( _target, expandDefineProperties( _definition, _target, toDefineProperty, arguments.length > 2 ? String( arguments[2] ) : _target.name ) ); } /** * Interpret `_target` as implementing a Java Functional Interface. A functional interface is an Interface with exactly * 1 function defined. Java allows lambda expressions to be generated for arguments of this type of interface. * This method allows normalizing a function or object to a "Functional Interface Object", so Java behavior can be * emulated. * This function will accept: * - `null`/`undefined` (then `null` is returned) * - A function (an 'instance' of _functionalInterface is returned, with this function in place). * - An object complying with _functionalInterface * * Any other argument will throw a {@link TypeError}. * @param {object|function} _target The target object or function. * @param {function} _functionalInterface The interface to use as functional interface. May only have a single method defined. * @param {boolean} [_strict=false] Optional: set to true to avoid a duck-type check, and only check `decl` * metadata for interfaces implemented. * @returns Either an object compliant with `_functionalInterface`, or `null`. * @throws {TypeError} A TypeError may occur if `_functionalInterface` is not a valid functional interface, * or if _target does not comply with the interface. * @memberof module:barejs.decl */ function asFunctional( _target, _functionalInterface, _strict ) { if ( !isInterface( _functionalInterface ) ) throw new TypeError( _functionalInterface + " is not an interface" ); var meta = InterfaceMetaData.get( _functionalInterface ); var fn = meta.members[ 0 ]; if ( meta.members.length !== 1 || fn.type !== "function" ) throw new TypeError( _functionalInterface.prototype + " is not a functional interface, functional interfaces have a single method" ); if ( _target === null || _target === undefined ) return null; // If this is a function, return an object that can be used instead. if ( typeof _target === "function" ) { var def = {}; def[fn.name] = { enumerable: true, value: _target }; return Object.create( _functionalInterface.prototype, def ); } if ( hasInterface( _target, _functionalInterface, _strict ) ) return _target; throw new TypeError( _target + " does not implement " + _functionalInterface.prototype ); } defineObject( exports, { // Exports isInterface: isInterface, isEnum: isEnum, isProxy: isProxy, is: is, hasBase: hasBase, hasInterface: hasInterface, proxy: proxy, abstractClass: abstractClass, declareClass: declareClass, declareInterface: declareInterface, declareEnum: declareEnum, defineObject: defineObject, asFunctional: asFunctional, // Convenience properties to define interface properties readOnlyProperty: readOnlyProperty, readWriteProperty: readWriteProperty, // Allows certain low level classes to disallow casting to them preventCast: preventCast }, "decl" ); // We do NOT want to add a displayName to methods from other modules, so use a separate defineObject defineObject( exports, /** @lends module:barejs.decl */ { // Helper methods/flags for property definitions /** * This convenience property is true if the environment supports property getters and setters. * @member {boolean} */ hasPropertySupport: ObjectPolyfill.propertyGetSetSupport, /** * decl re-exports {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty Object.defineProperty}. * * If the native version is not available, a fall-back is used. The fallback supports the same syntax as the original, but falls back to simple assignment * or deprecated constructs like {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/__defineGetter__ __defineGetter__}. * Be aware that property getters or setters may not be supported in some environments, which is indicated by {@link module:barejs.decl.hasPropertySupport hasPropertySupport} being false. * @function * @param {object} _target The object to define the property on * @param {string|Symbol} _key The name or {@link module:barejs.Symbol Symbol} to set * @param {object} _definition Object containing either a **value** property, or a **get** and/or **set** property (function). * @param {function} [_definition.get] A getter function, taking no arguments and returning the property value. * @param {function} [_definition.set] A setter function, taking a value as argument. * @param {*} [_definition.value] The value to assign to the property. * @param {boolean} [_definition.writable=false] (Only in combination with value) Whether assigning to the property is allowed. * For properties with get/set, the writable is implicit (by absence or presence of a setter function). * @param {boolean} [_definition.configurable=false] Whether the property may be altered via delete or a next defineProperty call. * @param {boolean} [_definition.enumerable=false] Whether the property shows up in object property enumerations. * @returns {object} The object the properties where defined on (_target). */ defineProperty: ObjectPolyfill.defineProperty, /** * decl re-exports {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties Object.defineProperties}. * * If the native version is not available, a fall-back is used. The fallback supports the same syntax as the original, and uses the {@link module:barejs.decl.defineProperty defineProperty} fallback. * @function * @param {object} _target The object to define the property on * @param {object} _definitions Object containing properties, each of which have a value that is a definition as passed to defineProperty. * @returns {object} The object the properties where defined on (_target). */ defineProperties: ObjectPolyfill.defineProperties, // Helper methods for object strictness (seal/freeze) /** * decl re-exports {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/seal Object.seal}. * * If the native version is not available, a **no-operation** function is used. The object is not altered in any way and simply returned. * @function * @param {object} _target The object to seal. * @returns {object} The object that was passed (_target). */ seal: ObjectPolyfill.seal, /** * decl re-exports {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isSealed Object.isSealed}. * A sealed object may not be altered by adding or removing properties. Existing properties may be altered (provided they are writable). * * If the native version is not available, a **no-operation** function is used. The object is not altered by the fallback, and it always returns false (since sealing objects is not supported). * * @function * @param {object} _target The object to evaluate. * @returns {boolean} True if the object (_target) is sealed, false otherwise. The fallback always returns false. */ isSealed: ObjectPolyfill.isSealed, /** * decl re-exports {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze Object.freeze}. * A frozen object may not be altered in any way. No properties may be added or removed (like seal), and all values are made read-only. * * If the native version is not available, a **no-operation** function is used. The object is not altered in any way and simply returned. * * @function * @param {object} _target The object to freeze. * @returns {object} The object that was passed (_target). */ freeze: ObjectPolyfill.freeze, /** * decl re-exports {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isFrozen Object.isFrozen}. * * If the native version is not available, a **no-operation** function is used. The object is not altered by the fallback, and it always returns false (since freezing objects is not supported). * @function * @param {object} _target The object to evaluate. * @returns {boolean} True if the object (_target) is frozen, false otherwise. The fallback always returns false. */ isFrozen: ObjectPolyfill.isFrozen } /*DO NOT ADD NAME*/ ); exports.freeze( exports ); // End of define }( Object, Array, String, Error, TypeError, __webpack_require__( 2 ), __webpack_require__( 3 ), __webpack_require__( 6 ), __webpack_require__( 8 ), __webpack_require__( 10 ), // Unreferenced: decl depends on the Array polyfills too. __webpack_require__( 12 ) ) ); /***/ }), /* 2 */ /***/ (function(module, exports, __webpack_require__) { // 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 ( (3) < 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( "