1 /*******************************************************************************
  2  * Class.js is a tool for generating JavaScript constructor functions that
  3  * can create fully encapsulated instance objects with an inheritance chain
  4  * similar to what one would expect from an object-oriented language without
  5  * requiring a cross-compiler or incurring much performance overhead.
  6  * @module java-class
  7  * @author Ranando D. King
  8  * @version 3.0.0
  9  ******************************************************************************/
 10 'use strict'
 11 
 12 /*
 13 	These are data keys that help define the Class. Public scope isn't listed
 14 	here because the Public scope of a Class is its prototype, and the Public
 15 	Static scope for the Class is the type constructor function that was
 16 	generated.
 17 */
 18 var METADATA = "__$METADATA$__",
 19 	PRIVATESCOPE = "__$PRIVATESCOPE$__",
 20 	PROTECTEDSCOPE = "__$PROTECTEDSCOPE$__",
 21 	STATICSCOPE = "__$STATICSCOPE$__";
 22 
 23 //List of words reserved for use in a Class definition object.
 24 var DefinitionWords = [ "Mode", "Implements", "Mixins", "Extends",
 25 						"Events", "Constructor", "StaticConstructor",
 26 						"Self", "Sibling", "Delegate"];
 27 var ReservedWords = [ "Mode", "Implements", "Mixins", "Extends",
 28 					  "Events", "Constructor", "StaticConstructor",
 29 					  "Self", "Sibling", "Delegate", "__name",
 30 					  "isClass", "classMode", "inheritsFrom",
 31 					  "getInterface", "isClassInstance", "__static" ];
 32 
 33 /**
 34  * Enum - Provides the ability to use syntax-checked enumeration values.
 35  *
 36  * @typedef {Object} Enum
 37  */
 38 var Enum = require("Enum");
 39 
 40 /**
 41  * WeakMap - Provides an ES5 shim for the features of ES6 WeakMaps.
 42  *
 43  * @typedef {Object} WeakMap
 44  */
 45 var WeakMap = require("WeakMap");
 46 
 47 /**
 48  * Privilege - An enumeration of the possible privilege levels of Class members.
 49  * Defaults to "None`"
 50  *
 51  * @typedef {Enum} Privilege
 52  * @prop {number} None - Specifies an unmarked privilege state.
 53  * @prop {number} Public - Marks the member as world visible.
 54  * @prop {number} Protected - Marks the member as descendant visible.
 55  * @prop {number} Private - Marks the member as exclusively for the defined Class.
 56  */
 57 var Privilege = new Enum("None", [ "Public", "Protected", "Private", "None" ]);
 58 
 59 /**
 60  * ClassModes - An enumeration of the inheritability of defined Class types.
 61  *
 62  * @typedef {Enum} ClassModes
 63  * @prop {number} Default - Sets unrestricted inheritability for the new Class.
 64  * @prop {number} Abstract - Sets required inheritability for the new Class.
 65  * @prop {number} Final - Restricts all inheritability of the new Class.
 66  */
 67 var ClassModes = new Enum("Default", ["Default", "Abstract", "Final"]);
 68 
 69 /**
 70  * ClassDefError - An exception class used to flag errors in Class definitions.
 71  *
 72  * @class ClassDefError
 73  * @extends Error
 74  * @param {string} message - String content of the error message to be printed
 75  * when thrown.
 76  * @param {string} key - Key in the Class definition object where the errors was
 77  * found.
 78  */
 79 function ClassDefError(message, key) {
 80 	this.name = "ClassDefError";
 81 	this.key = key;
 82 	this.message = (key?"While processing '" + key + "' - ": "") + message;
 83 }
 84 ClassDefError.prototype = Error.prototype;
 85 
 86 /**
 87  * ClassError - An exception class used to flag runtime errors in Class.
 88  *
 89  * @class ClassError
 90  * @extends Error
 91  * @param {string} message - String content of the error message to be printed
 92  * when thrown.
 93  */
 94 function ClassError(message) {
 95 	this.name = "ClassError";
 96 	this.message = "While running: " + message;
 97 }
 98 ClassError.prototype = Error.prototype;
 99 
100 function isSimpleFunction(obj) {
101 	return ((obj instanceof Function) &&
102 			!(obj.isClass || obj.isEnum || obj.isInterface || obj.isAttribute));
103 }
104 
105 function isValidType(type, value) {
106 	return ((value === null) || (value === undefined) ||
107 			(type.isInterface && type.isImplementedBy(value)) ||
108 			(type.isClass && (value instanceof type)) ||
109 			((type === Function) && (value instanceof Function)) ||
110 			((type === Date) && (value instanceof Date)) ||
111 			((type === String) && (typeof value == "string")) ||
112 			((typeof type == "string") && (type.toLowerCase() == typeof value)));
113 }
114 
115 function typeConstructor() {
116 	var classType = this.constructor;
117 	var name = classType.name;
118 	var metaData = classType[METADATA];
119 	var childDomain = arguments[arguments.length -1];
120 	var self = arguments[arguments.length -2];
121 	var argc = arguments.length - 2;
122 
123 	if (!(childDomain && (childDomain.__isInheritedDomain ||
124 						  childDomain.__isDescendant))) {
125 		childDomain = null;
126 		self = null;
127 		argc += 2;
128 	}
129 
130 	if (self && !self.isClassInstance) {
131 		self = null;
132 		++argc;
133 	}
134 
135 	if ((metaData.classMode === ClassModes.Abstract) &&
136 		(!childDomain || !(childDomain.__isInheritedDomain || childDomain.__isDescendant)))
137 		throw new SyntaxError("Cannot construct an Abstract Class!");
138 
139 	if (!metaData.Constructor ||
140 		((metaData.Constructor instanceof Box) &&
141 		 (metaData.Constructor.isPublic ||
142 		  (childDomain && childDomain.__isInheritedDomain && metaData.Constructor.isProtected)))) {
143 		initialize(this, childDomain, self);
144 		var instance = instances.get(this);
145 		if (metaData.Mixins)
146 			BlendMixins(definition.Mixins, instance);
147 
148 		Object.seal(instance);
149 
150 		var args = [].slice.call(arguments, 0, argc);
151 
152 		if (classConstructor) {
153 			if (!(childDomain && (childDomain.__isInheritedDomain || childDomain.__isDescendant))) {
154 				if (this.InheritsFrom) {
155 					var hasSuperFirst = /function\s+\w+\s*\((\w+\s*(,\s*\w+)*)?\)\s*{\s*this\s*\.\s*Super\s*\(/;
156 					var hasSuper = /\s*this\s*\.\s*Super\s*\(/;
157 					var constructorString = classConstructor.value.toString();
158 
159 					if (!hasSuper.test(constructorString)) {
160 						console.warn("Calling this.Super() for you!!!. You should be doing this in your " + name + " constructor!");
161 
162 						if (instance.Super.length)
163 							throw new Error("No default constructor available in " + name + "\'s super class!");
164 
165 						instance.Super();
166 					}
167 					else {
168 						if (!hasSuperFirst.test(constructorString))
169 							console.warn("Super should be the first call in your " + name + " constructor!")
170 					}
171 				}
172 				classConstructor.value.apply(instance, args);
173 			}
174 		}
175 		else if (this.InheritsFrom) {
176 			instance.Super();
177 		}
178 	}
179 	else if (classConstructor)
180 		throw new Error("Constructor '" + name + "' is not accessible!");
181 
182 	return this;
183 }
184 
185 function generateTypeConstructor(name) {
186 	var callErrorString = "This is a class instance generating function." +
187 						  "You must use 'new " + (name || "<ClassName>") +
188 						  "(...)' to use this function.";
189 
190 	eval("var retval = function " + name + "() {\n" +
191 		 "	if (!(this instanceof retval)) {\n" +
192 		 "		throw new ClassError(callErrorString);\n" +
193 		 "	}\n" +
194 		 "	\n" +
195 		 "	return typeConstructor.apply(this, arguments);\n" +
196 		 "};");
197 
198 	return retval;
199 }
200 
201 function validateDefinitionKeys(definition) {
202 	var mKey;
203 	for (var key in definition) {
204 		if (definition.hasOwnProperty(key)) {
205 			var member = definition[key];
206 
207 			/*
208 				If the member isn't an instance of Box, then it's either one of
209 				the Class definition description keys or it's just a public
210 				member that's been made public by default.
211 			*/
212 			if (!(member instanceof Box)) {
213 				switch(key) {
214 					case "Mode":
215 						//Since we're keeping the metadata, we only validate.
216 						if (!ClassModes.isMember(member))
217 							throw new ClassDefError("Invalid Mode!", "Mode");
218 						break;
219 					case "Implements":
220 						if (Array.isArray(member)) {
221 							for (mKey in member) {
222 								if (member.hasOwnProperty(mKey)) {
223 									if (!member[mKey].isInterface)
224 										throw new ClassDefError("Invalid interface!", key);
225 								}
226 							}
227 						}
228 						else
229 							throw new ClassDefError("Not an array of Interfaces!", key);
230 
231 						break;
232 					case "Mixins":
233 						if (!Array.isArray(member))
234 							throw new ClassDefError("Not an array!", key);
235 
236 						for (mKey in member) {
237 							if (member.hasOwnProperty(mKey)) {
238 								if (member[mKey] instanceof Function)
239 									throw new ClassDefError("Cannot mixin functions!", key);
240 							}
241 						}
242 						break;
243 					case "Extends":
244 						if (!(member instanceof Function))
245 							throw new ClassDefError("Cannot extend non-function!", key);
246 						break;
247 					case "Events":
248 						if (!Array.isArray(member))
249 							throw new ClassDefError("Not an array!", key);
250 
251 						for (var i = 0; i < member.length; i++) {
252 							if (typeof member[i] !== "string")
253 								throw new ClassDefError("Non-string event name!", key);
254 						}
255 						break;
256 					case "Constructor":
257 					case "StaticConstructor":
258 						if (!(member instanceof Function))
259 							throw new ClassDefError("Must be a function!", key);
260 
261 						definition[key] = modifyBox(null, {isPublic: true}, member);
262 						break;
263 					default:
264 						throw new ClassDefError("Unrecognized key!", key);
265 				}
266 			}
267 			else {
268 				switch(key) {
269 					case "Constructor":
270 						if (member.isStatic)
271 							throw new ClassDefError("Cannot be Static!", key);
272 
273 						if (member.isProperty)
274 							throw new ClassDefError("Cannot be a Property!", key);
275 
276 						if (!(member.value instanceof Function))
277 							throw new ClassDefError("Must be a function!", key);
278 
279 						break;
280 					case "StaticConstructor":
281 						if (member.isPrivate)
282 							throw new ClassDefError("Cannot be Private!", key);
283 
284 						if (member.isProtected)
285 							throw new ClassDefError("Cannot be Protected!", key);
286 
287 						if (member.isProperty)
288 							throw new ClassDefError("Cannot be a Property!", key);
289 
290 						if (member.isFinal)
291 							throw new ClassDefError("Cannot be Final!", key);
292 
293 						if (!(member.value instanceof Function))
294 							throw new ClassDefError("Must be a function!", key);
295 
296 						break;
297 					default:
298 						//Nothing to do here. It's just good form...
299 						break;
300 				}
301 			}
302 		}
303 	}
304 }
305 
306 function generateScopes(obj, definition) {
307 	var retval = {};
308 	retval[PRIVATESCOPE] = {};
309 	retval[PROTECTEDSCOPE] = {};
310 	retval[STATICSCOPE] = {};
311 
312 	validateDefinitionKeys(definition);
313 
314 	return retval;
315 }
316 
317 function generateMetaData(obj, name, definition) {
318 	obj[METADATA] = {
319 		name: name,
320 		definition: definition,
321 		isClass: true,
322 		classMode: function getClassMode() { return _classMode; },
323 		inheritsFrom: function inheritsFrom(obj) {
324 			return (definition.hasOwnProperty("Extends") &&
325 					definition.Extends.isClass &&
326 					((definition.Extends === obj) ||
327 					 (definition.Extends.inheritsFrom(obj))));
328 		},
329 		getInterface: function getInterface() {
330 			var intDef = {};
331 
332 			if (obj.InheritsFrom)
333 				intDef.Extends = [ obj.InheritsFrom.getInterface() ];
334 
335 			if (definition.Implements && Array.isArray(definition.Implements)) {
336 				if (!Array.isArray(intDef.Extends))
337 					intDef.Extends = [];
338 
339 				for (var i=0; i< definition.Implements.length; ++i)
340 					intDef.Extends.push(definition.Implements[i]);
341 			}
342 
343 			intDef.Properties = {};
344 			intDef.Methods = {};
345 
346 			for(var elementKey in definition) {
347 				if (definition.hasOwnProperty(elementKey)) {
348 					var element = definition[elementKey];
349 
350 					if ((elementKey != "Constructor") && (elementKey != "StaticConstructor") &&
351 						(element.isBox && element.isPublic)) {
352 
353 						if (element.isProperty)
354 							intDef.Properties[elementKey] = element.value.hasOwnProperty("set");
355 						else
356 							intDef.Methods[elementKey] = element.value.length;
357 					}
358 				}
359 			}
360 
361 			return new Interface(name + "_Interface", intDef);
362 		},
363 	};
364 
365 	Object.freeze(obj[METADATA]);
366 	Object.defineProperty(obj.prototype, "isClassInstance", { value: true });
367 }
368 
369 var Box = (function _Box() {
370 
371 	var internal = new WeakMap();
372 
373 	/**
374 	 * Box - The metadata object used to contain the description of a member of a
375 	 * defined Class type.
376 	 *
377 	 * @class Box
378 	 * @param {Object} params - Parameter block encoding the state of each flag.
379 	 * @property {Privilege} params.privilege - The Privilege for this member.
380 	 * @property {boolean} params.isFinal - Can it be overridden or changed?
381 	 * @property {boolean} params.isAbstract - Must it be overridden to be used?
382 	 * @property {boolean} params.isStatic - Is it owned by the Class type?
383 	 * @property {boolean} params.isProperty - Does it have side effects?
384 	 * @property {boolean} params.isDelegate - Will it be called externally?
385 	 * @property {string} params.type - The specific type returned by this member.
386 	 * @property {*} params.value - The statically assigned value for this member.
387 	 */
388 	var retval = function Box(params) {
389 		internal.set(this, {
390 			privilege: params.privilege,
391 			isFinal: !!params.isFinal,
392 			isAbstract: !!params.isAbstract,
393 			isStatic: !!params.isStatic,
394 			isProperty: !!params.isProperty,
395 			isDelegate: !!params.isDelegate,
396 			type: params.type,
397 			value: params.value
398 		});
399 
400 		if (this.isProperty && this.isFinal)
401 			throw new ClassDefError("Isn't this self-contradicting? \"Final Property\" just as allowable as (+1 === -1). Just don't!");
402 
403 		if (this.isAbstract && this.isProperty)
404 			throw new ClassDefError("Have ye gone daft? How can you override a property that the owning class doesn't even define?");
405 
406 		if (this.isAbstract && this.isFinal)
407 			throw new ClassDefError("Please make up your mind! Do you want to define it now(\"Final\") or later(\"Abstract\")?");
408 
409 		return this;
410 	};
411 
412 	Object.defineProperties(retval.prototype, {
413 		/**
414 		 * @memberof Box
415 		 * @property {boolean} isLocked - Flag signifying whether or not the Box
416 		 * can be edited further. Once locked, the box cannot be unlocked.
417 		 */
418 		isLocked: {
419 			enumerable: true,
420 			get: function getIsLocked() { return !!internal.get(this).isLocked; },
421 			set: function setIsLocked(val) {
422 				if (val)
423 					internal.get(this).isLocked = val;
424 			}
425 		},
426 		/**
427 		 * @memberof Box
428 		 * @property {boolean} isBox - Flag identifying that this a Box and not
429 		 * a JavaScript value.
430 		 */
431 		isBox: {
432 		   enumerable: true,
433 		   value: true
434 		},
435 		/**
436 		 * @memberof Box
437 		 * @property {boolean} noPrivilege - Internal flag set to true when no
438 		 * privilege level is specified for the member.
439 		 * @readonly
440 		 */
441 		noPrivilege: {
442 			enumerable: false,
443 			get: function getNoPrivilege() { return internal.get(this).privilege === Privilege.None; }
444 		},
445 		/**
446 		 * @memberof Box
447 		 * @property {boolean} isPrivate - Flag identifying that this member is
448 		 * only accessible internally on direct instances the declaring Class
449 		 * via 'this'.
450 		 */
451 		isPrivate: {
452 			enumerable: true,
453 			get: function getIsPrivate() { return internal.get(this).privilege === Privilege.Private; },
454 			set: function setIsPrivate(val) {
455 				var that = internal.get(this);
456 				if (!that.isLocked) {
457 					if (val) {
458 						if (that.privilege !== Privilege.Private) {
459 							if (that.privilege === Privilege.None) {
460 								that.privilege = Privilege.Private;
461 							}
462 							else {
463 								throw new ClassDefError("Member cannot be both 'Private' and '" +
464 														that.privilege.name + "' at the same time!");
465 							}
466 						}
467 					}
468 					else if (that.privilege === Privilege.Private) {
469 						that.privilege = Privilege.None;
470 					}
471 				}
472 			}
473 		},
474 		/**
475 		 * @memberof Box
476 		 * @property {boolean} isProtected - Flag identifying that this member
477 		 * is accessible internally via this in all instances of the declaring
478 		 * class.
479 		 */
480 		isProtected: {
481 			enumerable: true,
482 			get: function getIsProtected() { return internal.get(this).privilege === Privilege.Protected; },
483 			set: function setIsProtected(val) {
484 				var that = internal.get(this);
485 				if (!that.isLocked) {
486 					if (val) {
487 						if (that.privilege !== Privilege.Protected) {
488 							if (that.privilege === Privilege.None) {
489 								that.privilege = Privilege.Protected;
490 							}
491 							else {
492 								throw new ClassDefError("Member cannot be both 'Protected' and '" +
493 														that.privilege.name + "' at the same time!");
494 							}
495 
496 						}
497 					}
498 					else if (that.privilege === Privilege.Protected) {
499 						that.privilege = Privilege.None;
500 					}
501 				}
502 			}
503 		},
504 		/**
505 		 * @memberof Box
506 		 * @property {boolean} isPublic - Flag identifying that this member
507 		 * is accessible externally on all descendants of the declaring class.
508 		 */
509 		isPublic: {
510 			enumerable: true,
511 			get: function getIsPublic() { return internal.get(this).privilege === Privilege.Public; },
512 			set: function setIsPublic(val) {
513 				var that = internal.get(this);
514 				if (!that.isLocked) {
515 					if (val) {
516 						if (that.privilege !== Privilege.Public) {
517 							if (that.privilege === Privilege.None) {
518 								that.privilege = Privilege.Public;
519 							}
520 							else {
521 								throw new ClassDefError("Member cannot be both 'Public' and '" +
522 														that.privilege.name + "' at the same time!");
523 							}
524 
525 						}
526 					}
527 					else if (that.privilege === Privilege.Public) {
528 						that.privilege = Privilege.None;
529 					}
530 				}
531 			}
532 		},
533 		/**
534 		 * @memberof Box
535 		 * @property {boolean} isStatic - Flag identifying that this member
536 		 * is accessible via the declared Class type's constructor.
537 		 */
538 		isStatic: {
539 			enumerable: true,
540 			get: function getIsStatic() { return internal.get(this).isStatic; },
541 			set: function setIsStatic(val) {
542 				if (!this.isLocked)
543 					internal.get(this).isStatic = val;
544 			}
545 		},
546 		/**
547 		 * @memberof Box
548 		 * @property {boolean} isFinal - Flag identifying that this member
549 		 * cannot be overridden by declarations in subclasses of the declared
550 		 * Class.
551 		 */
552 		isFinal: {
553 			enumerable: true,
554 			get: function getIsFinal() { return internal.get(this).isFinal; },
555 			set: function setIsFinal(val) {
556 				var that = internal.get(this);
557 				if (!that.isLocked) {
558 					if (val) {
559 						if (that.isProperty)
560 							throw new ClassDefError("Isn't this self-contradicting? \"Final Property\" just as allowable as (+1 === -1). Just don't!");
561 
562 						if (that.isAbstract)
563 							throw new ClassDefError("Please make up your mind! Do you want to define it now(\"Final\") or later(\"Abstract\")?");
564 					}
565 
566 					that.isFinal = val;
567 				}
568 			}
569 		},
570 		/**
571 		 * @memberof Box
572 		 * @property {boolean} isAbstract - Flag identifying that this member
573 		 * must be overridden by declarations in subclasses of the declared
574 		 * Class.
575 		 */
576 		isAbstract: {
577 			enumerable: true,
578 			get: function getIsAbstract() { return internal.get(this).isAbstract; },
579 			set: function setIsAbstract(val) {
580 				var that = internal.get(this);
581 				if (!that.isLocked) {
582 					if (val) {
583 						if (that.isProperty)
584 							throw new ClassDefError("Have ye gone daft? How can you override a property that the owning class doesn't even define?");
585 
586 						if (that.isFinal)
587 							throw new ClassDefError("Please make up your mind! Do you want to define it now(\"Final\") or later(\"Abstract\")?");
588 					}
589 
590 					that.isAbstract = val;
591 				}
592 			}
593 		},
594 		/**
595 		 * @memberof Box
596 		 * @property {boolean} isProperty - Flag identifying that this member
597 		 * uses a getter and/or setter method(s) to define its value.
598 		 */
599 		isProperty: {
600 			enumerable: true,
601 			get: function getIsProperty() { return internal.get(this).isProperty; },
602 			set: function setIsProperty(val) {
603 				var that = internal.get(this);
604 				if (!that.isLocked) {
605 					if (val) {
606 						if (that.isFinal)
607 							throw new ClassDefError("Isn't this self-contradicting? \"Final Property\" just as allowable as (+1 === -1). Just don't!");
608 
609 						if (that.isAbstract)
610 							throw new ClassDefError("Have ye gone daft? How can you override a property that the owning class doesn't even define?");
611 					}
612 
613 					that.isProperty = val;
614 				}
615 			}
616 		},
617 		/**
618 		 * @memberof Box
619 		 * @property {boolean} isDelegate - Flag identifying that this member
620 		 * is prepared to be used as a callback function.
621 		 */
622 		isDelegate: {
623 			enumerable: true,
624 			get: function getIsDelegate() { return internal.get(this).isDelegate; },
625 			set: function setIsDelegate(val) {
626 				if (!this.isLocked)
627 					internal.get(this).isDelegate = val;
628 			}
629 		},
630 		/**
631 		 * @memberof Box
632 		 * @property {string} type - String identifying the data type expected
633 		 * returned when calling, getting or setting this member.
634 		 */
635 		type: {
636 			enumerable: true,
637 			get: function getType() { return internal.get(this).type; },
638 			set: function setType(val) {
639 				if (!this.isLocked) {
640 					if (isValidType(val, this.value))
641 						internal.get(this).type = val;
642 					else
643 						throw new ClassDefError("Failed to match type '" + val +"' to value '" + this.value +"'!");
644 				}
645 			}
646 		},
647 		/**
648 		 * @memberof Box
649 		 * @property {Object} value - Default value of member.
650 		 * @readonly
651 		 */
652 		value: {
653 			enumerable: true,
654 			get: function getValue() { return internal.get(this).value; }
655 		},
656 		/**
657 		 * Generates a string version of the values in this box for printing in
658 		 * a log or console.
659 		 * @memberof Box
660 		 * @function toString
661 		 * @returns {string}
662 		 * @readonly
663 		 */
664 		toString: {
665 			enumerable: true,
666 			value: function toString() {
667 				var typeName = "<unknown>";
668 				if (this.type instanceof Function) {
669 					if (this.type.isClass) {
670 						typeName = this.type.__name;
671 					}
672 					else {
673 						typeName = this.type.name;
674 					}
675 				}
676 
677 				var retval = {
678 					isPrivate: !!this.isPrivate,
679 					isProtected: !!this.isProtected,
680 					isPublic: !!this.isPublic,
681 					isStatic: !!this.isStatic,
682 					isFinal: !!this.isFinal,
683 					isProperty: !!this.isProperty,
684 					isDelegate: !!this.isDelegate,
685 					type: typeName,
686 					value: JSON.stringify(this.value)
687 				}
688 
689 				return JSON.stringify(retval, null, '\t');
690 			}
691 		}
692 	});
693 
694 	Object.seal(retval);
695 	return retval;
696 })();
697 
698 function modifyBox(box, params, val) {
699 	box = box || new Box({
700 		privilege: Privilege.Public,
701 		isFinal: false,
702 		isAbstract: false,
703 		isStatic: false,
704 		isProperty: false,
705 		isDelegate: false,
706 		type: null,
707 		value: val
708 	});
709 
710 	for (var key in params) {
711 		if (params.hasOwnProperty(key) && (key in box) && key != "value")
712 			box[key] = params[key];
713 	}
714 
715 	return box;
716 }
717 
718 module.exports = (function Class() {
719 	/**
720 	 * Class - A constructor factory designed to create functions that
721 	 * themselves create fully encapsulating, classical classes in JavaScript.
722 	 * It is not necessary to use 'new' when calling Class(...), but doing so
723 	 * will not interfere with how Class functions.
724 	 *
725 	 * @class Class
726 	 * @param {string=} name - Name of the new Class constructor function.
727 	 * @param {object} definition - Object describing the Class structure.
728 	 */
729 	function Class(name, definition) {
730 		if (this instanceof Class)
731 			console.warn("No need to use 'new' when declaring a new Class.");
732 
733 		if (arguments.length === 1) {
734 			if (typeof name == "object") {
735 				definition = name;
736 				name = "";
737 			}
738 			else {
739 				throw new ClassDefError("Where's the Class definition object? At least give me {}!");
740 			}
741 		}
742 
743 		var retval = generateTypeConstructor(name);
744 		var scopes = generateScopes(retval, definition);
745 		generateMetaData(retval, name, definition);
746 	}
747 
748 	/**
749 	 * Private - An access modifier function. Causes val to be encapsulated as
750 	 * only being accessible to direct instances of the class being described.
751 	 *
752 	 * @memberof Class
753 	 * @function
754 	 * @param {*} val - A Boxed or unboxed value.
755 	 */
756 	function Private(val) {
757 		var retval;
758 
759 		if (val && val.isBox) {
760 			retval = modifyBox(val, { privilege: Privilege.Private });
761 		}
762 		else {
763 			retval = modifyBox(null, { privilege: Privilege.Private }, val);
764 		}
765 
766 		return retval;
767 	}
768 
769 	/**
770 	 * Protected - An access modifier function. Causes val to be encapsulated as
771 	 * only being accessible to instances of the class being described and its
772 	 * subclasses.
773 	 *
774 	 * @memberof Class
775 	 * @function
776 	 * @param {*} val - A Boxed or unboxed value.
777 	 */
778 	function Protected(val) {
779 		var retval;
780 
781 		if (val && val.isBox) {
782 			retval = modifyBox(val, { privilege: Privilege.Protected });
783 		}
784 		else {
785 			retval = modifyBox(null, { privilege: Privilege.Protected }, val);
786 		}
787 
788 		return retval;
789 	}
790 
791 	/**
792 	 * Public - An access modifier function. Causes val to be encapsulated as
793 	 * being openly accessible from the class being described.
794 	 *
795 	 * @memberof Class
796 	 * @function
797 	 * @param {*} val - A Boxed or unboxed value.
798 	 */
799 	function Public(val) {
800 		var retval;
801 
802 		if (val && val.isBox) {
803 			retval = modifyBox(val, { privilege: Privilege.Public });
804 		}
805 		else {
806 			retval = modifyBox(null, { privilege: Privilege.Public }, val);
807 		}
808 
809 		return retval;
810 	}
811 
812 	/**
813 	 * Property - An access modifier function. Requires that val is an object
814 	 * with a getter and/or setter method. These are the only 2 members that are
815 	 * honored in the object.
816 	 *
817 	 * @memberof Class
818 	 * @function
819 	 * @param {Object} val - An object defining the access methods for the
820 	 * property. Must contain at leaset one of the following properties.
821 	 * @prop {function=} val.get - A function that calculates or retrieves the
822 	 * desired value. Takes no parameters.
823 	 * @prop {function=} val.set - A function that performs the needed actions
824 	 * to ensure that val.get returns the desired value. Takes a single
825 	 * parameter.
826 	 */
827 	function Property(val) {
828 		var retval;
829 
830 		if (val && val.isBox) {
831 			retval = modifyBox(val, { isProperty: true });
832 		}
833 		else {
834 			retval = modifyBox(null, { isProperty: true }, val);
835 		}
836 
837 		return retval;
838 	}
839 
840 	/**
841 	 * Static - An access modifier function. Causes val to be encapsulated as
842 	 * data owned by the constructor function and not the class's prototype.
843 	 *
844 	 * @memberof Class
845 	 * @function
846 	 * @param {*} val - A Boxed or unboxed value.
847 	 */
848 	function Static(val) {
849 		var retval;
850 
851 		if (val && val.isBox) {
852 			retval = modifyBox(val, { isStatic: true });
853 		}
854 		else {
855 			retval = modifyBox(null, { isStatic: true }, val);
856 		}
857 
858 		return retval;
859 	}
860 
861 	/**
862 	 * Final - An access modifier function. Causes val to be encapsulated as
863 	 * immutable. If val is a function, it is automatically Final.
864 	 *
865 	 * @memberof Class
866 	 * @function
867 	 * @param {*} val - A Boxed or unboxed value.
868 	 */
869 	function Final(val) {
870 		var retval;
871 
872 		if (val && val.isBox) {
873 			retval = modifyBox(val, { isFinal: true });
874 		}
875 		else {
876 			retval = modifyBox(null, { isFinal: true }, val);
877 		}
878 
879 		return retval;
880 	}
881 
882 	/**
883 	 * Abstract - An access modifier function. Causes val to be encapsulated as
884 	 * an undefined method. The parameter val must reference a function.
885 	 *
886 	 * @memberof Class
887 	 * @function
888 	 * @param {function} val - A Boxed or unboxed function.
889 	 */
890 	function Abstract(val) {
891 		var retval;
892 
893 		if (val && val.isBox) {
894 			retval = modifyBox(val, { isAbstract: true });
895 		}
896 		else {
897 			retval = modifyBox(null, { isAbstract: true }, val);
898 		}
899 
900 		return retval;
901 	}
902 
903 	/**
904 	 * Delegate - An access modifier function. Causes val to be encapsulated as
905 	 * bound method. Attempts to call this method, even after assignment to a
906 	 * variable, will always use the owning Class instance or type definition
907 	 * (if Static) as its scope. The parameter val must reference a function.
908 	 *
909 	 * @memberof Class
910 	 * @function
911 	 * @param {function} val - A Boxed or unboxed function.
912 	 */
913 	function Delegate(val) {
914 		var retval;
915 
916 		if (val && val.isBox) {
917 			retval = modifyBox(val, { isDelegate: true });
918 		}
919 		else {
920 			retval = modifyBox(null, { isDelegate: true }, val);
921 		}
922 
923 		return retval;
924 	}
925 
926 	/**
927 	 * Abstract - An access modifier function. Causes val to be tested to see if
928 	 * it matches the given type at definition time and at runtime, both on
929 	 * input and output.
930 	 *
931 	 * @memberof Class
932 	 * @function
933 	 * @param {string|Class} type - A type name string or Class type constructor.
934 	 * @param {*} val - A Boxed or unboxed value.
935 	 */
936 	function Type(type, val) {
937 		var retval = null;
938 
939 		if (type && (type.isClass || type.isInterface || (type === Function) ||
940 					 (type === String) || (type === Date) ||
941 					 ((typeof type == "string") &&
942 					  ((type.toLowerCase() === "string") ||
943 					   (type.toLowerCase() === "number") ||
944 					   (type.toLowerCase() === "boolean") ||
945 					   (type.toLowerCase() === "symbol"))))) {
946 			if (val instanceof Box) {
947 				if (val.isProperty || isSimpleFunction(val.value) || isValid(type, val.value)) {
948 					retval = modifyBox(val, { type: type });
949 				}
950 				else
951 					throw new TypeError("Expected value of type '" + type.__name + "'. Found " + val.value);
952 			}
953 			else if (isValid(type, val)) {
954 				retval = modifyBox(null, { type: type }, val);
955 			}
956 			else
957 				throw new TypeError("Expected value of type '" + type.__name + "'. Found " + val);
958 		}
959 		else
960 			throw new TypeError("Type must reference either a Class, an Interface, or an intrinsic type!");
961 
962 		return retval;
963 	}
964 
965 	function Initialize(_global) {
966 		Object.defineProperties(_global, {
967 			Private: {
968 				enumerable: true,
969 				value: Private
970 			},
971 			Protected: {
972 				enumerable: true,
973 				value: Protected
974 			},
975 			Public: {
976 				enumerable: true,
977 				value: Public
978 			},
979 			Property: {
980 				enumerable: true,
981 				value: Property
982 			},
983 			Static: {
984 				enumerable: true,
985 				value: Static
986 			},
987 			Final: {
988 				enumerable: true,
989 				value: Final
990 			},
991 			Abstract: {
992 				enumerable: true,
993 				value: Abstract
994 			},
995 			Delegate: {
996 				enumerable: true,
997 				value: Delegate
998 			},
999 			Type: {
1000 				enumerable: true,
1001 				value: Type
1002 			},
1003 			Modes: {
1004 				enumerable: true,
1005 				value: ClassModes
1006 			}
1007 		});
1008 	}
1009 
1010 	Initialize(Class);
1011 	Object.defineProperties(Class, {
1012 		Initialize: {
1013 			enumerable: true,
1014 			value: Initialize
1015 		}
1016 	});
1017 
1018 	Object.freeze(Class);
1019 	return Class;
1020 })();
1021