1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/addon-sdk/source/lib/sdk/deprecated/light-traits.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,599 @@ 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 +// `var` is being used in the module in order to make it reusable in 1.15 +// environments in which `let` is not yet supported. 1.16 + 1.17 +// Shortcut to `Object.prototype.hasOwnProperty.call`. 1.18 +// owns(object, name) would be the same as 1.19 +// Object.prototype.hasOwnProperty.call(object, name); 1.20 +var owns = Function.prototype.call.bind(Object.prototype.hasOwnProperty); 1.21 + 1.22 +/** 1.23 + * Whether or not given property descriptors are equivalent. They are 1.24 + * equivalent either if both are marked as 'conflict' or 'required' property 1.25 + * or if all the properties of descriptors are equal. 1.26 + * @param {Object} actual 1.27 + * @param {Object} expected 1.28 + */ 1.29 +function equivalentDescriptors(actual, expected) { 1.30 + return (actual.conflict && expected.conflict) || 1.31 + (actual.required && expected.required) || 1.32 + equalDescriptors(actual, expected); 1.33 +} 1.34 +/** 1.35 + * Whether or not given property descriptors define equal properties. 1.36 + */ 1.37 +function equalDescriptors(actual, expected) { 1.38 + return actual.get === expected.get && 1.39 + actual.set === expected.set && 1.40 + actual.value === expected.value && 1.41 + !!actual.enumerable === !!expected.enumerable && 1.42 + !!actual.configurable === !!expected.configurable && 1.43 + !!actual.writable === !!expected.writable; 1.44 +} 1.45 + 1.46 +// Utilities that throwing exceptions for a properties that are marked 1.47 +// as "required" or "conflict" properties. 1.48 +function throwConflictPropertyError(name) { 1.49 + throw new Error("Remaining conflicting property: `" + name + "`"); 1.50 +} 1.51 +function throwRequiredPropertyError(name) { 1.52 + throw new Error("Missing required property: `" + name + "`"); 1.53 +} 1.54 + 1.55 +/** 1.56 + * Generates custom **required** property descriptor. Descriptor contains 1.57 + * non-standard property `required` that is equal to `true`. 1.58 + * @param {String} name 1.59 + * property name to generate descriptor for. 1.60 + * @returns {Object} 1.61 + * custom property descriptor 1.62 + */ 1.63 +function RequiredPropertyDescriptor(name) { 1.64 + // Creating function by binding first argument to a property `name` on the 1.65 + // `throwConflictPropertyError` function. Created function is used as a 1.66 + // getter & setter of the created property descriptor. This way we ensure 1.67 + // that we throw exception late (on property access) if object with 1.68 + // `required` property was instantiated using built-in `Object.create`. 1.69 + var accessor = throwRequiredPropertyError.bind(null, name); 1.70 + return { get: accessor, set: accessor, required: true }; 1.71 +} 1.72 + 1.73 +/** 1.74 + * Generates custom **conflicting** property descriptor. Descriptor contains 1.75 + * non-standard property `conflict` that is equal to `true`. 1.76 + * @param {String} name 1.77 + * property name to generate descriptor for. 1.78 + * @returns {Object} 1.79 + * custom property descriptor 1.80 + */ 1.81 +function ConflictPropertyDescriptor(name) { 1.82 + // For details see `RequiredPropertyDescriptor` since idea is same. 1.83 + var accessor = throwConflictPropertyError.bind(null, name); 1.84 + return { get: accessor, set: accessor, conflict: true }; 1.85 +} 1.86 + 1.87 +/** 1.88 + * Tests if property is marked as `required` property. 1.89 + */ 1.90 +function isRequiredProperty(object, name) { 1.91 + return !!object[name].required; 1.92 +} 1.93 + 1.94 +/** 1.95 + * Tests if property is marked as `conflict` property. 1.96 + */ 1.97 +function isConflictProperty(object, name) { 1.98 + return !!object[name].conflict; 1.99 +} 1.100 + 1.101 +/** 1.102 + * Function tests whether or not method of the `source` object with a given 1.103 + * `name` is inherited from `Object.prototype`. 1.104 + */ 1.105 +function isBuiltInMethod(name, source) { 1.106 + var target = Object.prototype[name]; 1.107 + 1.108 + // If methods are equal then we know it's `true`. 1.109 + return target == source || 1.110 + // If `source` object comes form a different sandbox `==` will evaluate 1.111 + // to `false`, in that case we check if functions names and sources match. 1.112 + (String(target) === String(source) && target.name === source.name); 1.113 +} 1.114 + 1.115 +/** 1.116 + * Function overrides `toString` and `constructor` methods of a given `target` 1.117 + * object with a same-named methods of a given `source` if methods of `target` 1.118 + * object are inherited / copied from `Object.prototype`. 1.119 + * @see create 1.120 + */ 1.121 +function overrideBuiltInMethods(target, source) { 1.122 + if (isBuiltInMethod("toString", target.toString)) { 1.123 + Object.defineProperty(target, "toString", { 1.124 + value: source.toString, 1.125 + configurable: true, 1.126 + enumerable: false 1.127 + }); 1.128 + } 1.129 + 1.130 + if (isBuiltInMethod("constructor", target.constructor)) { 1.131 + Object.defineProperty(target, "constructor", { 1.132 + value: source.constructor, 1.133 + configurable: true, 1.134 + enumerable: false 1.135 + }); 1.136 + } 1.137 +} 1.138 + 1.139 +/** 1.140 + * Composes new trait with the same own properties as the original trait, 1.141 + * except that all property names appearing in the first argument are replaced 1.142 + * by "required" property descriptors. 1.143 + * @param {String[]} keys 1.144 + * Array of strings property names. 1.145 + * @param {Object} trait 1.146 + * A trait some properties of which should be excluded. 1.147 + * @returns {Object} 1.148 + * @example 1.149 + * var newTrait = exclude(["name", ...], trait) 1.150 + */ 1.151 +function exclude(names, trait) { 1.152 + var map = {}; 1.153 + 1.154 + Object.keys(trait).forEach(function(name) { 1.155 + 1.156 + // If property is not excluded (the array of names does not contain it), 1.157 + // or it is a "required" property, copy it to the property descriptor `map` 1.158 + // that will be used for creation of resulting trait. 1.159 + if (!~names.indexOf(name) || isRequiredProperty(trait, name)) 1.160 + map[name] = { value: trait[name], enumerable: true }; 1.161 + 1.162 + // For all the `names` in the exclude name array we create required 1.163 + // property descriptors and copy them to the `map`. 1.164 + else 1.165 + map[name] = { value: RequiredPropertyDescriptor(name), enumerable: true }; 1.166 + }); 1.167 + 1.168 + return Object.create(Trait.prototype, map); 1.169 +} 1.170 + 1.171 +/** 1.172 + * Composes new instance of `Trait` with a properties of a given `trait`, 1.173 + * except that all properties whose name is an own property of `renames` will 1.174 + * be renamed to `renames[name]` and a `"required"` property for name will be 1.175 + * added instead. 1.176 + * 1.177 + * For each renamed property, a required property is generated. If 1.178 + * the `renames` map two properties to the same name, a conflict is generated. 1.179 + * If the `renames` map a property to an existing unrenamed property, a 1.180 + * conflict is generated. 1.181 + * 1.182 + * @param {Object} renames 1.183 + * An object whose own properties serve as a mapping from old names to new 1.184 + * names. 1.185 + * @param {Object} trait 1.186 + * A new trait with renamed properties. 1.187 + * @returns {Object} 1.188 + * @example 1.189 + * 1.190 + * // Return trait with `bar` property equal to `trait.foo` and with 1.191 + * // `foo` and `baz` "required" properties. 1.192 + * var renamedTrait = rename({ foo: "bar", baz: null }), trait); 1.193 + * 1.194 + * // t1 and t2 are equivalent traits 1.195 + * var t1 = rename({a: "b"}, t); 1.196 + * var t2 = compose(exclude(["a"], t), { a: { required: true }, b: t[a] }); 1.197 + */ 1.198 +function rename(renames, trait) { 1.199 + var map = {}; 1.200 + 1.201 + // Loop over all the properties of the given `trait` and copy them to a 1.202 + // property descriptor `map` that will be used for the creation of the 1.203 + // resulting trait. Also, rename properties in the `map` as specified by 1.204 + // `renames`. 1.205 + Object.keys(trait).forEach(function(name) { 1.206 + var alias; 1.207 + 1.208 + // If the property is in the `renames` map, and it isn't a "required" 1.209 + // property (which should never need to be aliased because "required" 1.210 + // properties never conflict), then we must try to rename it. 1.211 + if (owns(renames, name) && !isRequiredProperty(trait, name)) { 1.212 + alias = renames[name]; 1.213 + 1.214 + // If the `map` already has the `alias`, and it isn't a "required" 1.215 + // property, that means the `alias` conflicts with an existing name for a 1.216 + // provided trait (that can happen if >=2 properties are aliased to the 1.217 + // same name). In this case we mark it as a conflicting property. 1.218 + // Otherwise, everything is fine, and we copy property with an `alias` 1.219 + // name. 1.220 + if (owns(map, alias) && !map[alias].value.required) { 1.221 + map[alias] = { 1.222 + value: ConflictPropertyDescriptor(alias), 1.223 + enumerable: true 1.224 + }; 1.225 + } 1.226 + else { 1.227 + map[alias] = { 1.228 + value: trait[name], 1.229 + enumerable: true 1.230 + }; 1.231 + } 1.232 + 1.233 + // Regardless of whether or not the rename was successful, we check to 1.234 + // see if the original `name` exists in the map (such a property 1.235 + // could exist if previous another property was aliased to this `name`). 1.236 + // If it isn't, we mark it as "required", to make sure the caller 1.237 + // provides another value for the old name, which methods of the trait 1.238 + // might continue to reference. 1.239 + if (!owns(map, name)) { 1.240 + map[name] = { 1.241 + value: RequiredPropertyDescriptor(name), 1.242 + enumerable: true 1.243 + }; 1.244 + } 1.245 + } 1.246 + 1.247 + // Otherwise, either the property isn't in the `renames` map (thus the 1.248 + // caller is not trying to rename it) or it is a "required" property. 1.249 + // Either way, we don't have to alias the property, we just have to copy it 1.250 + // to the map. 1.251 + else { 1.252 + // The property isn't in the map yet, so we copy it over. 1.253 + if (!owns(map, name)) { 1.254 + map[name] = { value: trait[name], enumerable: true }; 1.255 + } 1.256 + 1.257 + // The property is already in the map (that means another property was 1.258 + // aliased with this `name`, which creates a conflict if the property is 1.259 + // not marked as "required"), so we have to mark it as a "conflict" 1.260 + // property. 1.261 + else if (!isRequiredProperty(trait, name)) { 1.262 + map[name] = { 1.263 + value: ConflictPropertyDescriptor(name), 1.264 + enumerable: true 1.265 + }; 1.266 + } 1.267 + } 1.268 + }); 1.269 + return Object.create(Trait.prototype, map); 1.270 +} 1.271 + 1.272 +/** 1.273 + * Composes new resolved trait, with all the same properties as the original 1.274 + * `trait`, except that all properties whose name is an own property of 1.275 + * `resolutions` will be renamed to `resolutions[name]`. 1.276 + * 1.277 + * If `resolutions[name]` is `null`, the value is mapped to a property 1.278 + * descriptor that is marked as a "required" property. 1.279 + */ 1.280 +function resolve(resolutions, trait) { 1.281 + var renames = {}; 1.282 + var exclusions = []; 1.283 + 1.284 + // Go through each mapping in `resolutions` object and distribute it either 1.285 + // to `renames` or `exclusions`. 1.286 + Object.keys(resolutions).forEach(function(name) { 1.287 + 1.288 + // If `resolutions[name]` is a truthy value then it's a mapping old -> new 1.289 + // so we copy it to `renames` map. 1.290 + if (resolutions[name]) 1.291 + renames[name] = resolutions[name]; 1.292 + 1.293 + // Otherwise it's not a mapping but an exclusion instead in which case we 1.294 + // add it to the `exclusions` array. 1.295 + else 1.296 + exclusions.push(name); 1.297 + }); 1.298 + 1.299 + // First `exclude` **then** `rename` and order is important since 1.300 + // `exclude` and `rename` are not associative. 1.301 + return rename(renames, exclude(exclusions, trait)); 1.302 +} 1.303 + 1.304 +/** 1.305 + * Create a Trait (a custom property descriptor map) that represents the given 1.306 + * `object`'s own properties. Property descriptor map is a "custom", because it 1.307 + * inherits from `Trait.prototype` and it's property descriptors may contain 1.308 + * two attributes that is not part of the ES5 specification: 1.309 + * 1.310 + * - "required" (this property must be provided by another trait 1.311 + * before an instance of this trait can be created) 1.312 + * - "conflict" (when the trait is composed with another trait, 1.313 + * a unique value for this property is provided by two or more traits) 1.314 + * 1.315 + * Data properties bound to the `Trait.required` singleton exported by 1.316 + * this module will be marked as "required" properties. 1.317 + * 1.318 + * @param {Object} object 1.319 + * Map of properties to compose trait from. 1.320 + * @returns {Trait} 1.321 + * Trait / Property descriptor map containing all the own properties of the 1.322 + * given argument. 1.323 + */ 1.324 +function trait(object) { 1.325 + var map; 1.326 + var trait = object; 1.327 + 1.328 + if (!(object instanceof Trait)) { 1.329 + // If the passed `object` is not already an instance of `Trait`, we create 1.330 + // a property descriptor `map` containing descriptors for the own properties 1.331 + // of the given `object`. `map` is then used to create a `Trait` instance 1.332 + // after all properties are mapped. Note that we can't create a trait and 1.333 + // then just copy properties into it since that will fail for inherited 1.334 + // read-only properties. 1.335 + map = {}; 1.336 + 1.337 + // Each own property of the given `object` is mapped to a data property 1.338 + // whose value is a property descriptor. 1.339 + Object.keys(object).forEach(function (name) { 1.340 + 1.341 + // If property of an `object` is equal to a `Trait.required`, it means 1.342 + // that it was marked as "required" property, in which case we map it 1.343 + // to "required" property. 1.344 + if (Trait.required == 1.345 + Object.getOwnPropertyDescriptor(object, name).value) { 1.346 + map[name] = { 1.347 + value: RequiredPropertyDescriptor(name), 1.348 + enumerable: true 1.349 + }; 1.350 + } 1.351 + // Otherwise property is mapped to it's property descriptor. 1.352 + else { 1.353 + map[name] = { 1.354 + value: Object.getOwnPropertyDescriptor(object, name), 1.355 + enumerable: true 1.356 + }; 1.357 + } 1.358 + }); 1.359 + 1.360 + trait = Object.create(Trait.prototype, map); 1.361 + } 1.362 + return trait; 1.363 +} 1.364 + 1.365 +/** 1.366 + * Compose a property descriptor map that inherits from `Trait.prototype` and 1.367 + * contains property descriptors for all the own properties of the passed 1.368 + * traits. 1.369 + * 1.370 + * If two or more traits have own properties with the same name, the returned 1.371 + * trait will contain a "conflict" property for that name. Composition is a 1.372 + * commutative and associative operation, and the order of its arguments is 1.373 + * irrelevant. 1.374 + */ 1.375 +function compose(trait1, trait2/*, ...*/) { 1.376 + // Create a new property descriptor `map` to which all the own properties 1.377 + // of the passed traits are copied. This map will be used to create a `Trait` 1.378 + // instance that will be the result of this composition. 1.379 + var map = {}; 1.380 + 1.381 + // Properties of each passed trait are copied to the composition. 1.382 + Array.prototype.forEach.call(arguments, function(trait) { 1.383 + // Copying each property of the given trait. 1.384 + Object.keys(trait).forEach(function(name) { 1.385 + 1.386 + // If `map` already owns a property with the `name` and it is not 1.387 + // marked "required". 1.388 + if (owns(map, name) && !map[name].value.required) { 1.389 + 1.390 + // If the source trait's property with the `name` is marked as 1.391 + // "required", we do nothing, as the requirement was already resolved 1.392 + // by a property in the `map` (because it already contains a 1.393 + // non-required property with that `name`). But if properties are just 1.394 + // different, we have a name clash and we substitute it with a property 1.395 + // that is marked "conflict". 1.396 + if (!isRequiredProperty(trait, name) && 1.397 + !equivalentDescriptors(map[name].value, trait[name]) 1.398 + ) { 1.399 + map[name] = { 1.400 + value: ConflictPropertyDescriptor(name), 1.401 + enumerable: true 1.402 + }; 1.403 + } 1.404 + } 1.405 + 1.406 + // Otherwise, the `map` does not have an own property with the `name`, or 1.407 + // it is marked "required". Either way, the trait's property is copied to 1.408 + // the map (if the property of the `map` is marked "required", it is going 1.409 + // to be resolved by the property that is being copied). 1.410 + else { 1.411 + map[name] = { value: trait[name], enumerable: true }; 1.412 + } 1.413 + }); 1.414 + }); 1.415 + 1.416 + return Object.create(Trait.prototype, map); 1.417 +} 1.418 + 1.419 +/** 1.420 + * `defineProperties` is like `Object.defineProperties`, except that it 1.421 + * ensures that: 1.422 + * - An exception is thrown if any property in a given `properties` map 1.423 + * is marked as "required" property and same named property is not 1.424 + * found in a given `prototype`. 1.425 + * - An exception is thrown if any property in a given `properties` map 1.426 + * is marked as "conflict" property. 1.427 + * @param {Object} object 1.428 + * Object to define properties on. 1.429 + * @param {Object} properties 1.430 + * Properties descriptor map. 1.431 + * @returns {Object} 1.432 + * `object` that was passed as a first argument. 1.433 + */ 1.434 +function defineProperties(object, properties) { 1.435 + 1.436 + // Create a map into which we will copy each verified property from the given 1.437 + // `properties` description map. We use it to verify that none of the 1.438 + // provided properties is marked as a "conflict" property and that all 1.439 + // "required" properties are resolved by a property of an `object`, so we 1.440 + // can throw an exception before mutating object if that isn't the case. 1.441 + var verifiedProperties = {}; 1.442 + 1.443 + // Coping each property from a given `properties` descriptor map to a 1.444 + // verified map of property descriptors. 1.445 + Object.keys(properties).forEach(function(name) { 1.446 + 1.447 + // If property is marked as "required" property and we don't have a same 1.448 + // named property in a given `object` we throw an exception. If `object` 1.449 + // has same named property just skip this property since required property 1.450 + // is was inherited and there for requirement was satisfied. 1.451 + if (isRequiredProperty(properties, name)) { 1.452 + if (!(name in object)) 1.453 + throwRequiredPropertyError(name); 1.454 + } 1.455 + 1.456 + // If property is marked as "conflict" property we throw an exception. 1.457 + else if (isConflictProperty(properties, name)) { 1.458 + throwConflictPropertyError(name); 1.459 + } 1.460 + 1.461 + // If property is not marked neither as "required" nor "conflict" property 1.462 + // we copy it to verified properties map. 1.463 + else { 1.464 + verifiedProperties[name] = properties[name]; 1.465 + } 1.466 + }); 1.467 + 1.468 + // If no exceptions were thrown yet, we know that our verified property 1.469 + // descriptor map has no properties marked as "conflict" or "required", 1.470 + // so we just delegate to the built-in `Object.defineProperties`. 1.471 + return Object.defineProperties(object, verifiedProperties); 1.472 +} 1.473 + 1.474 +/** 1.475 + * `create` is like `Object.create`, except that it ensures that: 1.476 + * - An exception is thrown if any property in a given `properties` map 1.477 + * is marked as "required" property and same named property is not 1.478 + * found in a given `prototype`. 1.479 + * - An exception is thrown if any property in a given `properties` map 1.480 + * is marked as "conflict" property. 1.481 + * @param {Object} prototype 1.482 + * prototype of the composed object 1.483 + * @param {Object} properties 1.484 + * Properties descriptor map. 1.485 + * @returns {Object} 1.486 + * An object that inherits form a given `prototype` and implements all the 1.487 + * properties defined by a given `properties` descriptor map. 1.488 + */ 1.489 +function create(prototype, properties) { 1.490 + 1.491 + // Creating an instance of the given `prototype`. 1.492 + var object = Object.create(prototype); 1.493 + 1.494 + // Overriding `toString`, `constructor` methods if they are just inherited 1.495 + // from `Object.prototype` with a same named methods of the `Trait.prototype` 1.496 + // that will have more relevant behavior. 1.497 + overrideBuiltInMethods(object, Trait.prototype); 1.498 + 1.499 + // Trying to define given `properties` on the `object`. We use our custom 1.500 + // `defineProperties` function instead of build-in `Object.defineProperties` 1.501 + // that behaves exactly the same, except that it will throw if any 1.502 + // property in the given `properties` descriptor is marked as "required" or 1.503 + // "conflict" property. 1.504 + return defineProperties(object, properties); 1.505 +} 1.506 + 1.507 +/** 1.508 + * Composes new trait. If two or more traits have own properties with the 1.509 + * same name, the new trait will contain a "conflict" property for that name. 1.510 + * "compose" is a commutative and associative operation, and the order of its 1.511 + * arguments is not significant. 1.512 + * 1.513 + * **Note:** Use `Trait.compose` instead of calling this function with more 1.514 + * than one argument. The multiple-argument functionality is strictly for 1.515 + * backward compatibility. 1.516 + * 1.517 + * @params {Object} trait 1.518 + * Takes traits as an arguments 1.519 + * @returns {Object} 1.520 + * New trait containing the combined own properties of all the traits. 1.521 + * @example 1.522 + * var newTrait = compose(trait_1, trait_2, ..., trait_N) 1.523 + */ 1.524 +function Trait(trait1, trait2) { 1.525 + 1.526 + // If the function was called with one argument, the argument should be 1.527 + // an object whose properties are mapped to property descriptors on a new 1.528 + // instance of Trait, so we delegate to the trait function. 1.529 + // If the function was called with more than one argument, those arguments 1.530 + // should be instances of Trait or plain property descriptor maps 1.531 + // whose properties should be mixed into a new instance of Trait, 1.532 + // so we delegate to the compose function. 1.533 + 1.534 + return trait2 === undefined ? trait(trait1) : compose.apply(null, arguments); 1.535 +} 1.536 + 1.537 +Object.freeze(Object.defineProperties(Trait.prototype, { 1.538 + toString: { 1.539 + value: function toString() { 1.540 + return "[object " + this.constructor.name + "]"; 1.541 + } 1.542 + }, 1.543 + 1.544 + /** 1.545 + * `create` is like `Object.create`, except that it ensures that: 1.546 + * - An exception is thrown if this trait defines a property that is 1.547 + * marked as required property and same named property is not 1.548 + * found in a given `prototype`. 1.549 + * - An exception is thrown if this trait contains property that is 1.550 + * marked as "conflict" property. 1.551 + * @param {Object} 1.552 + * prototype of the compared object 1.553 + * @returns {Object} 1.554 + * An object with all of the properties described by the trait. 1.555 + */ 1.556 + create: { 1.557 + value: function createTrait(prototype) { 1.558 + return create(undefined === prototype ? Object.prototype : prototype, 1.559 + this); 1.560 + }, 1.561 + enumerable: true 1.562 + }, 1.563 + 1.564 + /** 1.565 + * Composes a new resolved trait, with all the same properties as the original 1.566 + * trait, except that all properties whose name is an own property of 1.567 + * `resolutions` will be renamed to the value of `resolutions[name]`. If 1.568 + * `resolutions[name]` is `null`, the property is marked as "required". 1.569 + * @param {Object} resolutions 1.570 + * An object whose own properties serve as a mapping from old names to new 1.571 + * names, or to `null` if the property should be excluded. 1.572 + * @returns {Object} 1.573 + * New trait with the same own properties as the original trait but renamed. 1.574 + */ 1.575 + resolve: { 1.576 + value: function resolveTrait(resolutions) { 1.577 + return resolve(resolutions, this); 1.578 + }, 1.579 + enumerable: true 1.580 + } 1.581 +})); 1.582 + 1.583 +/** 1.584 + * @see compose 1.585 + */ 1.586 +Trait.compose = Object.freeze(compose); 1.587 +Object.freeze(compose.prototype); 1.588 + 1.589 +/** 1.590 + * Constant singleton, representing placeholder for required properties. 1.591 + * @type {Object} 1.592 + */ 1.593 +Trait.required = Object.freeze(Object.create(Object.prototype, { 1.594 + toString: { 1.595 + value: Object.freeze(function toString() { 1.596 + return "<Trait.required>"; 1.597 + }) 1.598 + } 1.599 +})); 1.600 +Object.freeze(Trait.required.toString.prototype); 1.601 + 1.602 +exports.Trait = Object.freeze(Trait);