1 /* 2 * Filename: Attribute.js 3 * Created By: Ranando D. King 4 * License: Apache 2.0 5 * 6 * Copyright 2015 Ranando D. King 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 */ 20 21 var Class = require("./Class"); 22 var Private = Class.Private; 23 var Property = Class.Property; 24 25 var Attribute = (function() { 26 var ExpandScopeElement = function(dest, scope, key, _this) { 27 if (dest.hasOwnProperty(key) && scope[key].isBox) { 28 var prop = scope[key]; 29 var isFn = (prop.value instanceof Function && !prop.value.isClass); 30 var isFinal = prop.isFinal || isFn; 31 32 //Handle the default case. The privilege level doesn't matter for that. 33 var propConfig = { 34 enumerable: true, 35 configurable: !prop.isFinal 36 }; 37 38 if (prop.isProperty) { 39 propConfig.configurable = false; 40 41 if (_this) { 42 if ((prop.value.get instanceof Function) && prop.value.get.isFunctor) 43 propConfig.get = prop.value.get.rescope(_this); 44 else 45 propConfig.get = prop.value.get; 46 47 if ((prop.value.set instanceof Function) && prop.value.set.isFunctor) 48 propConfig.set = prop.value.set.rescope(_this); 49 else 50 propConfig.set = prop.value.set; 51 } 52 else { 53 if (prop.value.get) 54 propConfig.get = prop.value.get; 55 56 if (prop.value.set) 57 propConfig.set = prop.value.set; 58 59 if (prop.value.value) { 60 propConfig.writable = prop.value.wrtable; 61 62 if ((prop.value.value instanceof Function) && prop.value.value.isFunctor) 63 propConfig.value = prop.value.value.rescope(_this); 64 else 65 propConfig.value = prop.value.value; 66 } 67 } 68 } 69 else { 70 propConfig.writable = !isFinal; 71 72 if ((prop.value instanceof Function) && prop.value.isFunctor) 73 propConfig.value = prop.value.rescope(_this); 74 else 75 propConfig.value = prop.value; 76 } 77 78 delete dest[key]; 79 Object.defineProperty(dest, key, propConfig); 80 } 81 }; 82 83 var makeRedirect = function(prop, dest, key) { 84 var isProtected = false; 85 var propConfig = { 86 enumerable: true 87 }; 88 89 var getRedirect = function() { 90 var instance = instances.get(this); 91 var retval = instance[key]; 92 93 //If we're returning a function, make sure it's called against the correct object! 94 if ((retval instanceof Function) && !retval.isClass && !retval.isFunctor) 95 retval = new Functor(instance, retval); 96 97 return retval; 98 }; 99 100 var setRedirect = function(val) { 101 var instance = ((prop.isStatic && this.__isClassDomain)?staticScope : 102 ((this.__isClassDomain)?this:instances.get(this))) || staticScope; 103 instance[key] = val; 104 }; 105 106 if (isProtected || (prop.isPublic && !prop.isStatic)) { 107 propConfig.get = new Functor(null, getRedirect); 108 109 if (!prop.isFinal) 110 propConfig.set = new Functor(null, setRedirect); 111 } 112 else { 113 propConfig.get = getRedirect; 114 115 if (!prop.isFinal) 116 propConfig.set = setRedirect; 117 } 118 119 //Put a new property on the destination that references the 120 //redirected object. 121 dest[key] = new Box(prop.isPublic?Privilege.Public: (prop.isProtected?Privilege.Protected:Privilege.Private), 122 prop.isStatic, false, true, propConfig); 123 }; 124 125 var $$ = function Attribute(name, definition) { 126 if (!name || !name.length) 127 throw new SyntaxError("Attributes must be assigned a name!"); 128 129 if (definition.contains("Constructor")) 130 throw new SyntaxError("Attributes are static objects and cannot contain a non-static constructor!"); 131 132 var scope = new WeakMap(); 133 134 definition["$source"] = Private(Property({ get: function getSource() { return scope.get(this); } })); 135 136 var Special = { Extends:0, Implements:0, Events:0, Mixins:0, StaticConstructor:0 }; 137 138 //attrib is the Class of the Attribute! 139 var attrib = Class.call(this, name, definition); 140 141 var _$ = function(obj) { 142 var attr = new attrib(); 143 var instance = {}; 144 145 scope.set(attr, obj); 146 147 for (var member in definition) { 148 if (definition.hasOwnProperty(member) && definition[member]) { 149 if (!(member in Special) && definition[member].isBox) { 150 makeRedirect(definition[member], instance, member); 151 ExpandScopeElement(instance, instance, member, attr); 152 } 153 } 154 } 155 156 instance.prototype = obj; 157 158 if (!("$attributes" in instance)) 159 Object.defineProperty(instance, "$attributes", { value: [] }); 160 161 instance["$attributes"].push(name); 162 Object.seal(instance); 163 return instance; 164 }; 165 166 Object.seal(_$); 167 return _$; 168 }; 169 170 Object.seal($$); 171 return $$; 172 })(); 173 174 module.exports = Attribute; 175