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

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial