1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/addon-sdk/source/lib/sdk/deprecated/traits.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,187 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +"use strict"; 1.9 + 1.10 +module.metadata = { 1.11 + "stability": "deprecated" 1.12 +}; 1.13 + 1.14 +const { 1.15 + compose: _compose, 1.16 + override: _override, 1.17 + resolve: _resolve, 1.18 + trait: _trait, 1.19 + //create: _create, 1.20 + required, 1.21 +} = require('./traits/core'); 1.22 + 1.23 +const defineProperties = Object.defineProperties, 1.24 + freeze = Object.freeze, 1.25 + create = Object.create; 1.26 + 1.27 +/** 1.28 + * Work around bug 608959 by defining the _create function here instead of 1.29 + * importing it from traits/core. For docs on this function, see the create 1.30 + * function in that module. 1.31 + * 1.32 + * FIXME: remove this workaround in favor of importing the function once that 1.33 + * bug has been fixed. 1.34 + */ 1.35 +function _create(proto, trait) { 1.36 + let properties = {}, 1.37 + keys = Object.getOwnPropertyNames(trait); 1.38 + for each(let key in keys) { 1.39 + let descriptor = trait[key]; 1.40 + if (descriptor.required && 1.41 + !Object.prototype.hasOwnProperty.call(proto, key)) 1.42 + throw new Error('Missing required property: ' + key); 1.43 + else if (descriptor.conflict) 1.44 + throw new Error('Remaining conflicting property: ' + key); 1.45 + else 1.46 + properties[key] = descriptor; 1.47 + } 1.48 + return Object.create(proto, properties); 1.49 +} 1.50 + 1.51 +/** 1.52 + * Placeholder for `Trait.prototype` 1.53 + */ 1.54 +let TraitProto = Object.prototype; 1.55 + 1.56 +function Get(key) this[key] 1.57 +function Set(key, value) this[key] = value 1.58 + 1.59 +/** 1.60 + * Creates anonymous trait descriptor from the passed argument, unless argument 1.61 + * is a trait constructor. In later case trait's already existing properties 1.62 + * descriptor is returned. 1.63 + * This is module's internal function and is used as a gateway to a trait's 1.64 + * internal properties descriptor. 1.65 + * @param {Function} $ 1.66 + * Composed trait's constructor. 1.67 + * @returns {Object} 1.68 + * Private trait property of the composition. 1.69 + */ 1.70 +function TraitDescriptor(object) 1.71 + ( 1.72 + 'function' == typeof object && 1.73 + (object.prototype == TraitProto || object.prototype instanceof Trait) 1.74 + ) ? object._trait(TraitDescriptor) : _trait(object) 1.75 + 1.76 +function Public(instance, trait) { 1.77 + let result = {}, 1.78 + keys = Object.getOwnPropertyNames(trait); 1.79 + for each (let key in keys) { 1.80 + if ('_' === key.charAt(0) && '__iterator__' !== key ) 1.81 + continue; 1.82 + let property = trait[key], 1.83 + descriptor = { 1.84 + configurable: property.configurable, 1.85 + enumerable: property.enumerable 1.86 + }; 1.87 + if (property.get) 1.88 + descriptor.get = property.get.bind(instance); 1.89 + if (property.set) 1.90 + descriptor.set = property.set.bind(instance); 1.91 + if ('value' in property) { 1.92 + let value = property.value; 1.93 + if ('function' === typeof value) { 1.94 + descriptor.value = property.value.bind(instance); 1.95 + descriptor.writable = property.writable; 1.96 + } else { 1.97 + descriptor.get = Get.bind(instance, key); 1.98 + descriptor.set = Set.bind(instance, key); 1.99 + } 1.100 + } 1.101 + result[key] = descriptor; 1.102 + } 1.103 + return result; 1.104 +} 1.105 + 1.106 +/** 1.107 + * This is private function that composes new trait with privates. 1.108 + */ 1.109 +function Composition(trait) { 1.110 + function Trait() { 1.111 + let self = _create({}, trait); 1.112 + self._public = create(Trait.prototype, Public(self, trait)); 1.113 + delete self._public.constructor; 1.114 + if (Object === self.constructor) 1.115 + self.constructor = Trait; 1.116 + else 1.117 + return self.constructor.apply(self, arguments) || self._public; 1.118 + return self._public; 1.119 + } 1.120 + defineProperties(Trait, { 1.121 + prototype: { value: freeze(create(TraitProto, { 1.122 + constructor: { value: constructor, writable: true } 1.123 + }))}, // writable is `true` to avoid getters in custom ES5 1.124 + displayName: { value: (trait.constructor || constructor).name }, 1.125 + compose: { value: compose, enumerable: true }, 1.126 + override: { value: override, enumerable: true }, 1.127 + resolve: { value: resolve, enumerable: true }, 1.128 + required: { value: required, enumerable: true }, 1.129 + _trait: { value: function _trait(caller) 1.130 + caller === TraitDescriptor ? trait : undefined 1.131 + } 1.132 + }); 1.133 + return freeze(Trait); 1.134 +} 1.135 + 1.136 +/** 1.137 + * Composes new trait out of itself and traits / property maps passed as an 1.138 + * arguments. If two or more traits / property maps have properties with the 1.139 + * same name, the new trait will contain a "conflict" property for that name. 1.140 + * This is a commutative and associative operation, and the order of its 1.141 + * arguments is not significant. 1.142 + * @params {Object|Function} 1.143 + * List of Traits or property maps to create traits from. 1.144 + * @returns {Function} 1.145 + * New trait containing the combined properties of all the traits. 1.146 + */ 1.147 +function compose() { 1.148 + let traits = Array.slice(arguments, 0); 1.149 + traits.push(this); 1.150 + return Composition(_compose.apply(null, traits.map(TraitDescriptor))); 1.151 +} 1.152 + 1.153 +/** 1.154 + * Composes a new trait with all of the combined properties of `this` and the 1.155 + * argument traits. In contrast to `compose`, `override` immediately resolves 1.156 + * all conflicts resulting from this composition by overriding the properties of 1.157 + * later traits. Trait priority is from left to right. I.e. the properties of 1.158 + * the leftmost trait are never overridden. 1.159 + * @params {Object} trait 1.160 + * @returns {Object} 1.161 + */ 1.162 +function override() { 1.163 + let traits = Array.slice(arguments, 0); 1.164 + traits.push(this); 1.165 + return Composition(_override.apply(null, traits.map(TraitDescriptor))); 1.166 +} 1.167 + 1.168 +/** 1.169 + * Composes new resolved trait, with all the same properties as this 1.170 + * trait, except that all properties whose name is an own property of 1.171 + * `resolutions` will be renamed to `resolutions[name]`. If it is 1.172 + * `resolutions[name]` is `null` value is changed into a required property 1.173 + * descriptor. 1.174 + */ 1.175 +function resolve(resolutions) 1.176 + Composition(_resolve(resolutions, TraitDescriptor(this))) 1.177 + 1.178 +/** 1.179 + * Base Trait, that all the traits are composed of. 1.180 + */ 1.181 +const Trait = Composition({ 1.182 + /** 1.183 + * Internal property holding public API of this instance. 1.184 + */ 1.185 + _public: { value: null, configurable: true, writable: true }, 1.186 + toString: { value: function() '[object ' + this.constructor.name + ']' } 1.187 +}); 1.188 +TraitProto = Trait.prototype; 1.189 +exports.Trait = Trait; 1.190 +