addon-sdk/source/lib/sdk/deprecated/traits.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 "use strict";
     7 module.metadata = {
     8   "stability": "deprecated"
     9 };
    11 const {
    12   compose: _compose,
    13   override: _override,
    14   resolve: _resolve,
    15   trait: _trait,
    16   //create: _create,
    17   required,
    18 } = require('./traits/core');
    20 const defineProperties = Object.defineProperties,
    21       freeze = Object.freeze,
    22       create = Object.create;
    24 /**
    25  * Work around bug 608959 by defining the _create function here instead of
    26  * importing it from traits/core.  For docs on this function, see the create
    27  * function in that module.
    28  *
    29  * FIXME: remove this workaround in favor of importing the function once that
    30  * bug has been fixed.
    31  */
    32 function _create(proto, trait) {
    33   let properties = {},
    34       keys = Object.getOwnPropertyNames(trait);
    35   for each(let key in keys) {
    36     let descriptor = trait[key];
    37     if (descriptor.required &&
    38         !Object.prototype.hasOwnProperty.call(proto, key))
    39       throw new Error('Missing required property: ' + key);
    40     else if (descriptor.conflict)
    41       throw new Error('Remaining conflicting property: ' + key);
    42     else
    43       properties[key] = descriptor;
    44   }
    45   return Object.create(proto, properties);
    46 }
    48 /**
    49  * Placeholder for `Trait.prototype`
    50  */
    51 let TraitProto = Object.prototype;
    53 function Get(key) this[key]
    54 function Set(key, value) this[key] = value
    56 /**
    57  * Creates anonymous trait descriptor from the passed argument, unless argument
    58  * is a trait constructor. In later case trait's already existing properties
    59  * descriptor is returned.
    60  * This is module's internal function and is used as a gateway to a trait's
    61  * internal properties descriptor.
    62  * @param {Function} $
    63  *    Composed trait's constructor.
    64  * @returns {Object}
    65  *    Private trait property of the composition.
    66  */
    67 function TraitDescriptor(object)
    68   (
    69     'function' == typeof object &&
    70     (object.prototype == TraitProto || object.prototype instanceof Trait)
    71   ) ? object._trait(TraitDescriptor) : _trait(object)
    73 function Public(instance, trait) {
    74   let result = {},
    75       keys = Object.getOwnPropertyNames(trait);
    76   for each (let key in keys) {
    77     if ('_' === key.charAt(0) && '__iterator__' !== key )
    78       continue;
    79     let property = trait[key],
    80         descriptor = {
    81           configurable: property.configurable,
    82           enumerable: property.enumerable
    83         };
    84     if (property.get)
    85       descriptor.get = property.get.bind(instance);
    86     if (property.set)
    87       descriptor.set = property.set.bind(instance);
    88     if ('value' in property) {
    89       let value = property.value;
    90       if ('function' === typeof value) {
    91         descriptor.value = property.value.bind(instance);
    92         descriptor.writable = property.writable;
    93       } else {
    94         descriptor.get = Get.bind(instance, key);
    95         descriptor.set = Set.bind(instance, key);
    96       }
    97     }
    98     result[key] = descriptor;
    99   }
   100   return result;
   101 }
   103 /**
   104  * This is private function that composes new trait with privates.
   105  */
   106 function Composition(trait) {
   107   function Trait() {
   108     let self = _create({}, trait);
   109     self._public = create(Trait.prototype, Public(self, trait));
   110     delete self._public.constructor;
   111     if (Object === self.constructor)
   112       self.constructor = Trait;
   113     else
   114       return self.constructor.apply(self, arguments) || self._public;
   115     return self._public;
   116   }
   117   defineProperties(Trait, {
   118     prototype: { value: freeze(create(TraitProto, {
   119       constructor: { value: constructor, writable: true }
   120     }))}, // writable is `true` to avoid getters in custom ES5
   121     displayName: { value: (trait.constructor || constructor).name },
   122     compose: { value: compose, enumerable: true },
   123     override: { value: override, enumerable: true },
   124     resolve: { value: resolve, enumerable: true },
   125     required: { value: required, enumerable: true },
   126     _trait: { value: function _trait(caller)
   127         caller ===  TraitDescriptor ? trait : undefined
   128     }
   129   });
   130   return freeze(Trait);
   131 }
   133 /**
   134  * Composes new trait out of itself and traits / property maps passed as an
   135  * arguments. If two or more traits / property maps have properties with the
   136  * same name, the new trait will contain a "conflict" property for that name.
   137  * This is a commutative and associative operation, and the order of its
   138  * arguments is not significant.
   139  * @params {Object|Function}
   140  *    List of Traits or property maps to create traits from.
   141  * @returns {Function}
   142  *    New trait containing the combined properties of all the traits.
   143  */
   144 function compose() {
   145   let traits = Array.slice(arguments, 0);
   146   traits.push(this);
   147   return Composition(_compose.apply(null, traits.map(TraitDescriptor)));
   148 }
   150 /**
   151  * Composes a new trait with all of the combined properties of `this` and the
   152  * argument traits. In contrast to `compose`, `override` immediately resolves
   153  * all conflicts resulting from this composition by overriding the properties of
   154  * later traits. Trait priority is from left to right. I.e. the properties of
   155  * the leftmost trait are never overridden.
   156  * @params {Object} trait
   157  * @returns {Object}
   158  */
   159 function override() {
   160   let traits = Array.slice(arguments, 0);
   161   traits.push(this);
   162   return Composition(_override.apply(null, traits.map(TraitDescriptor)));
   163 }
   165 /**
   166  * Composes new resolved trait, with all the same properties as this
   167  * trait, except that all properties whose name is an own property of
   168  * `resolutions` will be renamed to `resolutions[name]`. If it is
   169  * `resolutions[name]` is `null` value is changed into a required property
   170  * descriptor.
   171  */
   172 function resolve(resolutions)
   173   Composition(_resolve(resolutions, TraitDescriptor(this)))
   175 /**
   176  * Base Trait, that all the traits are composed of.
   177  */
   178 const Trait = Composition({
   179   /**
   180    * Internal property holding public API of this instance.
   181    */
   182   _public: { value: null, configurable: true, writable: true },
   183   toString: { value: function() '[object ' + this.constructor.name + ']' }
   184 });
   185 TraitProto = Trait.prototype;
   186 exports.Trait = Trait;

mercurial