jaydata-core
Version:
Cross-platform HTML5 data-management, JavaScript Language Query (JSLQ) support for OData, SQLite, WebSQL, IndexedDB, YQL and Facebook (packaged for Node.JS)
1,134 lines (993 loc) • 65.2 kB
JavaScript
(function init($data, global) {
function il(msg) {
if (typeof intellisense !== 'undefined') {
if (!intellisense.i) {
intellisense.i = 0;
}
intellisense.i = intellisense.i + 1;
intellisense.logMessage(msg + ":" + intellisense.i);
}
}
function MemberDefinition(memberDefinitionData, definedClass) {
///<field name="name" type="String">*</field>
///<field name="dataType" type="Object">*</field>
///<field name="elementType" type="Object"></field>
///<field name="kind" type="String" />
///<field name="classMember" type="Boolean" />
///<field name="set" type="Function" />
///<field name="get" type="Function" />
///<field name="value" type="Object" />
///<field name="initialValue" type="Object" />
///<field name="method" type="Function" />
///<field name="enumerable" type="Boolean" />
///<field name="configurable" type="Boolean" />
///<field name="key" type="Boolean" />
///<field name="computed" type="Boolean" />
///<field name="storeOnObject" type="Boolean">[false] if false value is stored in initData, otherwise on the object</field>
///<field name="monitorChanges" type="Boolean">[true] if set to false propertyChange events are not raise and property tracking is disabled</field>
this.kind = MemberTypes.property;
//this.definedBy = definedClass;
Object.defineProperty(this, 'definedBy', { value: definedClass, enumerable: false, configurable: false, writable: false });
if (memberDefinitionData) {
if (typeof memberDefinitionData === 'function' || typeof memberDefinitionData.asFunction === 'function') {
this.method = memberDefinitionData;
this.kind = MemberTypes.method;
} else {
this.enumerable = true;
this.configurable = true;
if (typeof memberDefinitionData === "number") {
this.value = memberDefinitionData;
this.type = $data.Number;
this.dataType = $data.Number;
} else if (typeof memberDefinitionData === "string") {
this.value = memberDefinitionData;
this.dataType = $data.String;
this.type = $data.String;
} else {
for (var item in memberDefinitionData) {
if (memberDefinitionData.hasOwnProperty(item)) {
this[item] = memberDefinitionData[item];
}
}
}
}
if (this.type !== undefined) {
this.dataType = this.dataType || this.type;
} else {
this.type = this.dataType;
}
this.originalType = this.type;
if (this.elementType !== undefined) {
this.originalElementType = this.elementType;
}
}
}
MemberDefinition.prototype.createPropertyDescriptor = function (classFunction, value) {
///<returns type="Object" />
var pd = this;
var result = {
enumerable: this.enumerable == undefined ? true : this.enumerable,
configurable: this.configurable == undefined ? true : this.configurable
};
if (this.set && this.get) {
result.set = this.set;
result.get = this.get;
} else if ("value" in this || value) {
result.value = value || this.value;
//TODO
//result.writable = this.writable;
result.writable = true;
}
else {
result.set = function (value) { this.storeProperty(pd, value); };
result.get = function () { return this.retrieveProperty(pd); };
}
return result;
};
MemberDefinition.prototype.createStorePropertyDescriptor = function (value) {
var pd = this;
return { enumerable: false, writable: true, configurable: pd.configurable, value: value };
};
MemberDefinition.prototype.createGetMethod = function () {
var pd = this;
return {
enumerable: false, writable: false, configurable: false,
value: function (callback, tran) { return this.getProperty(pd, callback, tran); }
};
};
MemberDefinition.prototype.createSetMethod = function () {
var pd = this;
return {
enumerable: false, writable: false, configurable: false,
value: function (value, callback, tran) { return this.setProperty(pd, value, callback, tran); }
};
};
MemberDefinition.translateDefinition = function (memDef, name, classFunction) {
var holder = classFunction;
var memberDefinition;
if (memDef.type && Container.isTypeRegistered(memDef.type)) {
holder = Container.resolveType(memDef.type);
if (typeof holder.translateDefinition === 'function') {
memberDefinition = holder.translateDefinition.apply(holder, arguments);
memberDefinition.name = memberDefinition.name || name;
} else {
holder = classFunction;
}
}
if (!(memberDefinition instanceof MemberDefinition)) {
memberDefinition = new MemberDefinition(memberDefinition || memDef, holder);
memberDefinition.name = name;
}
classFunction.resolverThunks = classFunction.resolverThunks || [];
classFunction.childResolverThunks = classFunction.childResolverThunks || [];
var t = memberDefinition.type;
var et = memberDefinition.elementType;
function addChildThunk(referencedType) {
if (referencedType && referencedType.isAssignableTo && $data.Entity && referencedType.isAssignableTo($data.Entity)) {
classFunction.childResolverThunks.push(function () {
if (referencedType.resolveForwardDeclarations) {
referencedType.resolveForwardDeclarations();
}
});
}
}
addChildThunk(t);
addChildThunk(et);
if ("string" === typeof t) {
if ("@" === t[0]) {
memberDefinition.type = t.substr(1);
memberDefinition.dataType = t.substr(1);
} else {
//forward declared types get this callback when type is registered
classFunction.resolverThunks.push(function () {
var rt = classFunction.container.resolveType(t);
addChildThunk(rt);
memberDefinition.type = rt;
memberDefinition.dataType = rt;
});
}
}
if (et) {
if ("string" === typeof et) {
if ("@" === et[0]) {
memberDefinition.elementType = et.substr(1);
} else {
//forward declared types get this callback when type is registered
classFunction.resolverThunks.push(function () {
var rt = classFunction.container.resolveType(et);
addChildThunk(rt);
memberDefinition.elementType = rt;
});
}
}
}
//if (!classFunction)
classFunction.resolveForwardDeclarations = function () {
classFunction.resolveForwardDeclarations = function () { };
$data.Trace.log("resolving: " + classFunction.fullName);
this.resolverThunks.forEach(function (thunk) {
thunk();
});
//this.resolverThunks = [];
this.childResolverThunks.forEach(function (thunk) {
thunk();
});
//this.childResolverThunks = [];
}
return memberDefinition;
};
MemberDefinition.prototype.toJSON = function () {
var property = {};
for (var name in this) {
if (name !== 'defineBy' && name !== 'storageModel') {
if ((name === 'type' || name === 'dataType') && (this[name] && typeof this[name] === 'function')) {
try {
property[name] = Container.resolveName(this[name]);
} catch (e) {
property[name] = this[name];
}
} else {
property[name] = this[name];
}
}
}
return property;
}
//TODO global/window
$data.MemberDefinition = window["MemberDefinition"] = MemberDefinition;
var memberDefinitionPrefix = '$';
function MemberDefinitionCollection() { };
MemberDefinitionCollection.prototype = {
clearCache: function () {
this.arrayCache = undefined;
this.pubMapPropsCache = undefined;
this.keyPropsCache = undefined;
this.propByTypeCache = undefined;
this.pubMapMethodsCache = undefined;
this.pubMapPropNamesCache = undefined;
},
asArray: function () {
if (!this.arrayCache) {
this.arrayCache = [];
for (var i in this) {
if (i.indexOf(memberDefinitionPrefix) === 0)
this.arrayCache.push(this[i]);
}
}
return this.arrayCache;
},
getPublicMappedProperties: function () {
if (!this.pubMapPropsCache) {
this.pubMapPropsCache = [];
for (var i in this) {
if (i.indexOf(memberDefinitionPrefix) === 0 && this[i].kind == 'property' && !this[i].notMapped && this[i].enumerable)
this.pubMapPropsCache.push(this[i]);
}
}
return this.pubMapPropsCache;// || (this.pubMapPropsCache = this.asArray().filter(function (m) { return m.kind == 'property' && !m.notMapped && m.enumerable; }));
},
getPublicMappedPropertyNames: function () {
if (!this.pubMapPropNamesCache) {
this.pubMapPropNamesCache = [];
for (var i in this) {
if (i.indexOf(memberDefinitionPrefix) === 0 && this[i].kind == 'property' && !this[i].notMapped && this[i].enumerable)
this.pubMapPropNamesCache.push(this[i].name);
}
}
return this.pubMapPropNamesCache;
},
getKeyProperties: function () {
if (!this.keyPropsCache) {
this.keyPropsCache = [];
for (var i in this) {
if (i.indexOf(memberDefinitionPrefix) === 0 && this[i].kind == 'property' && this[i].key)
this.keyPropsCache.push(this[i]);
}
}
return this.keyPropsCache;
//return this.keyPropsCache || (this.keyPropsCache = this.asArray().filter(function (m) { return m.kind == 'property' && m.key; }));
},
getPublicMappedMethods: function () {
if (!this.pubMapMethodsCache) {
this.pubMapMethodsCache = [];
for (var i in this) {
if (i.indexOf(memberDefinitionPrefix) === 0 && this[i].kind == 'method' && this[i].method/* && this.hasOwnProperty(i)*/)
this.pubMapMethodsCache.push(this[i]);
}
}
return this.pubMapMethodsCache;
},
getPropertyByType: function (type) {
if (!this.propByTypeCache) {
this.propByTypeCache = [];
for (var i in this) {
if (i.indexOf(memberDefinitionPrefix) === 0 && this[i].dataType == type)
this.propByTypeCache.push(this[i]);
}
}
return this.propByTypeCache;
//return this.propByTypeCache || (this.propByTypeCache = this.asArray().filter(function (m) { return m.dataType == type; }));
},
getMember: function (name) { return this[memberDefinitionPrefix + name]; },
setMember: function (value) { this[memberDefinitionPrefix + value.name] = value; }
};
MemberDefinitionCollection.prototype.constructor = MemberDefinitionCollection;
$data.MemberDefinitionCollection = window["MemberDefinitionCollection"] = MemberDefinitionCollection;
function ClassEngineBase() {
this.classNames = {};
}
function MemberTypes() {
///<field name="method" type="string" />
///<field name="property" type="string" />
///<field name="field" type="string" />
///<field name="complexProperty" type="string" />
}
MemberTypes.__enum = true;
MemberTypes.method = "method";
MemberTypes.property = "property";
MemberTypes.navProperty = "navProperty";
MemberTypes.complexProperty = "complexProperty";
MemberTypes.field = "field";
$data.MemberTypes = MemberTypes;
//function classToJSON() {
// var ret = {};
// for (var i in this) {
// if (this.hasOwnProperty(i)) {
// ret[i] = this[i];
// }
// }
// return ret;
//}
//$data.Base.toJSON = classToJSON;
ClassEngineBase.prototype = {
//getClass: function (classReference) {
//},
//getProperties: function (classFunction) {
// return classFunction.propertyDefinitions;
//},
define: function (className, baseClass, container, instanceDefinition, classDefinition) {
/// <signature>
/// <summary>Creates a Jaydata type</summary>
/// <param name="className" type="String">Name of the class</param>
/// <param name="baseClass" type="Function">Basetype of the class</param>
/// <param name="interfaces" type="Object" elementType="Function" />
/// <param name="instanceDefinition" type="Object">Class definition (properties, methods, etc)</param>
/// <param name="classDefinition" type="Object">Class static definition</param>
/// <example>
///
/// var t = new $data.Class.define('Types.A', $data.Base, null, {
/// constructor: function(){ },
/// func1: function(){ },
/// member1: { type: 'string' }
/// }, {
/// staticFunc1: function() {}
/// })
///
/// </example>
/// </signature>
return this.defineEx(className, [{ type: baseClass }], container, instanceDefinition, classDefinition);
},
defineEx: function (className, baseClasses, container, instanceDefinition, classDefinition) {
/// <signature>
/// <summary>Creates a Jaydata type</summary>
/// <param name="className" type="String">Name of the class</param>
/// <param name="baseClasses" type="Array" elementType="Functions">Basetypes of the class. First is a real base, others are mixins</param>
/// <param name="interfaces" type="Object" elementType="Function" />
/// <param name="instanceDefinition" type="Object">Class definition (properties, methods, etc)</param>
/// <param name="classDefinition" type="Object">Class static definition</param>
/// <example>
///
/// var t = new $data.Class.define('Types.A', [$data.Base, $data.Mixin1, $data.Mixin2], null, {
/// constructor: function(){ },
/// func1: function(){ },
/// member1: { type: 'string' }
/// }, {
/// staticFunc1: function() {}
/// })
///
/// </example>
/// </signature>
/// <signature>
/// <summary>Creates a Jaydata type</summary>
/// <param name="className" type="String">Name of the class</param>
/// <param name="baseClasses" type="Array" elementType="Object">Basetypes of the class. First is a real base, others are mixins or propagations</param>
/// <param name="interfaces" type="Object" elementType="Function" />
/// <param name="instanceDefinition" type="Object">Class definition (properties, methods, etc)</param>
/// <param name="classDefinition" type="Object">Class static definition</param>
/// <example>
///
/// var t = new $data.Class.define('Types.A', [
/// { type: $data.Base, params: [1, 'secondParameterValue', new ConstructorParameter(0)] },
/// { type: $data.Mixin1, },
/// { type: $data.Mixin2, },
/// { type: $data.Propagation1, params: [new ConstructorParameter(1)], propagateTo:'Propagation1' },
/// { type: $data.Propagation2, params: ['firstParameterValue'], propagateTo:'Propagation2' }
/// ], null, {
/// constructor: function(){ },
/// func1: function(){ },
/// member1: { type: 'string' }
/// }, {
/// staticFunc1: function() {}
/// })
///
/// </example>
/// </signature>
container = container || $data.Container;
if (baseClasses.length == 0) {
baseClasses.push({ type: $data.Base });
} else if (baseClasses.length > 0 && !baseClasses[0].type) {
baseClasses[0].type = $data.Base;
}
for (var i = 0, l = baseClasses.length; i < l; i++) {
if (typeof baseClasses[i] === 'function')
baseClasses[i] = { type: baseClasses[i] };
}
var providedCtor = instanceDefinition ? instanceDefinition.constructor : undefined;
var classNameParts = className.split('.');
var shortClassName = classNameParts.splice(classNameParts.length - 1, 1)[0];
var root = container === $data.Container ? window : container;
for (var i = 0; i < classNameParts.length; i++) {
var part = classNameParts[i];
if (!root[part]) {
var ns = {};
ns.__namespace = true;
root[part] = ns;
}
root = root[part];
}
var classFunction = null;
classFunction = this.classFunctionBuilder(shortClassName, baseClasses, classDefinition, instanceDefinition);
classFunction.fullName = className;
classFunction.namespace = classNameParts.join('.'); //classname splitted
classFunction.name = shortClassName;
classFunction.container = container;
classFunction.container.registerType(className, classFunction);
this.buildType(classFunction, baseClasses, instanceDefinition, classDefinition);
if (typeof intellisense !== 'undefined') {
if (instanceDefinition && instanceDefinition.constructor) {
intellisense.annotate(classFunction, instanceDefinition.constructor);
}
}
root[shortClassName] = this.classNames[className] = classFunction;
//classFunction.toJSON = classToJSON;
var baseCount = classFunction.baseTypes.length;
for (var i = 0; i < baseCount; i++) {
var b = classFunction.baseTypes[i];
if ("inheritedTypeProcessor" in b) {
b.inheritedTypeProcessor(classFunction);
}
}
//classFunction.prototype.constructor = instanceDefinition.constructor;
//classFunction.constructor = instanceDefinition.constructor;
//classFunction.toJSON = function () { return classFunction.memberDefinitions.filter( function(md) { return md; };
return classFunction;
},
classFunctionBuilder: function (name, base, classDefinition, instanceDefinition) {
var body = this.bodyBuilder(base, classDefinition, instanceDefinition);
return new Function('base', 'classDefinition', 'instanceDefinition', 'name', 'return function ' + name + ' (){ ' +
body + ' \n}; ')(base, classDefinition, instanceDefinition, name);
},
bodyBuilder: function (bases, classDefinition, instanceDefinition) {
var mixin = '';
var body = '';
var propagation = '';
for (var i = 0, l = bases.length; i < l; i++) {
var base = bases[i];
var index = i;
if (index == 0) { //ctor func
if (base && base.type && base.type !== $data.Base && base.type.fullName) {
body += ' var baseArguments = $data.typeSystem.createCtorParams(arguments, base[' + index + '].params, this); \n';
body += ' ' + base.type.fullName + '.apply(this, baseArguments); \n';
}
} else {
if (base && base.type && base.propagateTo) {
//propagation
propagation += ' ' + (!propagation ? 'var ' : '' + '') + 'propagationArguments = $data.typeSystem.createCtorParams(arguments, base[' + index + '].params, this); \n';
propagation += ' this["' + base.propagateTo + '"] = Object.create(' + base.type.fullName + '.prototype); \n' +
' ' + base.type.fullName + '.apply(this["' + base.propagateTo + '"], propagationArguments); \n';
}
else if (base && base.type && base.type.memberDefinitions && base.type.memberDefinitions.$constructor && !base.propagateTo) {
//mixin
mixin += ' ' + base.type.fullName + '.memberDefinitions.$constructor.method.apply(this); \n';
}
}
}
if (instanceDefinition && instanceDefinition.constructor != Object)
body += " instanceDefinition.constructor.apply(this, arguments); \n";
return '\n //mixins \n' + mixin + '\n //construction \n' + body + '\n //propagations \n' + propagation;
},
buildType: function (classFunction, baseClasses, instanceDefinition, classDefinition) {
var baseClass = baseClasses[0].type;
classFunction.inheritsFrom = baseClass;
if (baseClass) {
classFunction.prototype = Object.create(baseClass.prototype);
classFunction.memberDefinitions = Object.create(baseClass.memberDefinitions || new MemberDefinitionCollection());
classFunction.memberDefinitions.clearCache();
var staticDefs = baseClass.staticDefinitions;
if (staticDefs) {
staticDefs = staticDefs.asArray();
if (staticDefs) {
for (var i = 0; i < staticDefs.length; i++) {
this.buildMember(classFunction, staticDefs[i], undefined, 'staticDefinitions');
}
}
}
classFunction.baseTypes = baseClass.baseTypes ? [].concat(baseClass.baseTypes) : [];
for (var i = 0; i < baseClasses.length; i++) {
classFunction.baseTypes.push(baseClasses[i].type);
}
//classFunction.baseTypes = (baseClass.baseTypes || []).concat(baseClasses.map(function (base) { return base.type; }));
if (!classFunction.isAssignableTo) {
Object.defineProperty(classFunction, "isAssignableTo", {
value: function (type) {
return this === type || this.baseTypes.indexOf(type) >= 0;
},
writable: false,
enumerable: false,
configurable: false
});
}
}
if (classDefinition) {
this.buildStaticMembers(classFunction, classDefinition);
if (classDefinition.constructor)
classFunction.classConstructor = classDefinition.constructor;
}
if (instanceDefinition) {
this.buildInstanceMembers(classFunction, instanceDefinition);
}
var mixins = [].concat(baseClasses);
mixins.shift();
if (Object.keys(mixins).length > 0)
this.buildInstanceMixins(classFunction, mixins);
classFunction.__class = true;
classFunction.prototype.constructor = classFunction;
Object.defineProperty(classFunction.prototype, "getType", {
value: function () {
return classFunction;
},
writable: false,
enumerable: false,
configurable: false
});
},
addMethod: function (holder, name, method, propagation) {
if (!propagation || (typeof intellisense !== 'undefined')) {
holder[name] = method;
} else {
holder[name] = function () {
return method.apply(this[propagation], arguments);
};
}
},
addProperty: function (holder, name, propertyDescriptor, propagation) {
//holder[name] = {};
if (propagation) {
propertyDescriptor.configurable = true;
if (propertyDescriptor.get) {
var origGet = propertyDescriptor.get;
propertyDescriptor.get = function () {
if (!this[propagation])
Guard.raise(new Exception("not inicialized"));
return origGet.apply(this[propagation], arguments);
};
}
if (propertyDescriptor.set) {
var origSet = propertyDescriptor.set;
propertyDescriptor.set = function () {
if (!this[propagation])
Guard.raise(new Exception("not inicialized"));
origSet.apply(this[propagation], arguments);
};
}
}
Object.defineProperty(holder, name, propertyDescriptor);
},
addField: function (holder, name, field) {
Guard.raise("not implemented");
},
buildMethod: function (classFunction, memberDefinition, propagation) {
///<param name="classFunction" type="Function">The object that will receive member</param>
///<param name="memberDefinition" type="MemberDefinition">the newly added member</param>
var holder = memberDefinition.classMember ? classFunction : classFunction.prototype;
this.addMethod(holder, memberDefinition.name, memberDefinition.method, propagation);
},
buildProperty: function (classFunction, memberDefinition, propagation) {
///<param name="classFunction" type="Function">The object that will receive member</param>
///<param name="memberDefinition" type="MemberDefinition">the newly added member</param>
var holder = memberDefinition.classMember ? classFunction : classFunction.prototype;
var pd = memberDefinition.createPropertyDescriptor(classFunction);
this.addProperty(holder, memberDefinition.name, pd, propagation);
//if lazyload TODO
if (!memberDefinition.classMember && classFunction.__setPropertyfunctions == true && memberDefinition.withoutGetSetMethod !== true &&
!('get_' + memberDefinition.name in holder || 'set_' + memberDefinition.name in holder)) {
var pdGetMethod = memberDefinition.createGetMethod();
this.addProperty(holder, 'get_' + memberDefinition.name, pdGetMethod, propagation);
var pdSetMethod = memberDefinition.createSetMethod();
this.addProperty(holder, 'set_' + memberDefinition.name, pdSetMethod, propagation);
}
},
buildMember: function (classFunction, memberDefinition, propagation, memberCollectionName) {
///<param name="memberDefinition" type="MemberDefinition" />
memberCollectionName = memberCollectionName || 'memberDefinitions';
classFunction[memberCollectionName] = classFunction[memberCollectionName] || new MemberDefinitionCollection();
classFunction[memberCollectionName].setMember(memberDefinition);
switch (memberDefinition.kind) {
case MemberTypes.method:
this.buildMethod(classFunction, memberDefinition, propagation);
break;
case MemberTypes.navProperty:
case MemberTypes.complexProperty:
case MemberTypes.property:
this.buildProperty(classFunction, memberDefinition, propagation);
break;
default: Guard.raise("Unknown member type: " + memberDefinition.kind + "," + memberDefinition.name);
}
},
buildStaticMembers: function (classFunction, memberListDefinition) {
///<param name="classFunction" type="Object">The class constructor that will be extended</param>
///<param name="memberListDefinition" type="Object"></param>
var t = this;
for (var item in memberListDefinition) {
if (memberListDefinition.hasOwnProperty(item)) {
var memberDefinition = MemberDefinition.translateDefinition(memberListDefinition[item], item, classFunction);
memberDefinition.classMember = true;
t.buildMember(classFunction, memberDefinition, undefined, 'staticDefinitions');
}
}
},
buildInstanceMembers: function (classFunction, memberListDefinition) {
///<param name="classFunction" type="Function">The class constructor whose prototype will be extended</param>
///<param name="memberListDefinition" type="Object"></param>
///pinning t outside of the closure seems actually faster then passing in the this and referencing
var t = this;
for (var item in memberListDefinition) {
if (memberListDefinition.hasOwnProperty(item)) {
var memberDefinition = MemberDefinition.translateDefinition(memberListDefinition[item], item, classFunction);
t.buildMember(classFunction, memberDefinition, undefined, 'memberDefinitions');
}
}
},
copyMembers: function (sourceType, targetType) {
///<param name="sourceType" type="Function" />
///<param name="targetType" type="Function" />
function il(msg) {
if (typeof intellisense === 'undefined') {
return;
}
intellisense.logMessage(msg);
}
Object.keys(sourceType.prototype).forEach(function (item, i, src) {
if (item !== 'constructor' && item !== 'toString') {
il("copying item:" + item);
targetType.prototype[item] = sourceType[item];
}
});
},
buildInstanceMixins: function (classFunction, mixinList) {
///<param name="classFunction" type="Function">The class constructor whose prototype will be extended</param>
///<param name="mixinList" type="Array"></param>
classFunction.mixins = classFunction.mixins || [];
classFunction.propagations = classFunction.propagations || [];
for (var i = 0; i < mixinList.length; i++) {
var item = mixinList[i];
//if (classFunction.memberDefinitions.getMember(item.type.name)) {
if (item.propagateTo) {
this.buildInstancePropagation(classFunction, item);
classFunction.propagations.push(item);
classFunction.propagations[item.type.name] = true;
} else {
this.buildInstanceMixin(classFunction, item);
classFunction.mixins.push(item);
classFunction.mixins[item.type.name] = true;
}
};
},
buildInstanceMixin: function (classFunction, typeObj) {
///<param name="classFunction" type="Function">The class constructor whose prototype will be extended</param>
///<param name="typeObj" type="Object"></param>
var memberDefs = typeObj.type.memberDefinitions.asArray();
for (var i = 0, l = memberDefs.length; i < l; i++) {
var itemName = memberDefs[i].name;
if (itemName !== 'constructor' && !classFunction.memberDefinitions.getMember(itemName)) {
this.buildMember(classFunction, memberDefs[i]);
}
}
if (typeObj.type.staticDefinitions) {
var staticDefs = typeObj.type.staticDefinitions.asArray();
for (var i = 0, l = staticDefs.length; i < l; i++) {
var itemName = staticDefs[i].name;
if (itemName !== 'constructor' && !classFunction.memberDefinitions.getMember(itemName)) {
this.buildMember(classFunction, staticDefs[i], undefined, 'staticDefinitions');
}
}
}
},
buildInstancePropagation: function (classFunction, typeObj) {
///<param name="classFunction" type="Function">The class constructor whose prototype will be extended</param>
///<param name="typeObj" type="Object"></param>
var memberDefs = typeObj.type.memberDefinitions.asArray();
for (var i = 0, l = memberDefs.length; i < l; i++) {
var itemName = memberDefs[i].name;
if (itemName !== 'constructor' && !classFunction.memberDefinitions.getMember(itemName)) {
this.buildMember(classFunction, memberDefs[i], typeObj.propagateTo);
}
}
}
};
$data.Class = Class = new ClassEngineBase();
//(function (global) {
global = window;
function ContainerCtor(parentContainer) {
var parent = parentContainer;
if (parent) {
parent.addChildContainer(this);
}
var classNames = {};
var consolidatedClassNames = [];
var classTypes = [];
this.classNames = classNames;
this.consolidatedClassNames = consolidatedClassNames;
this.classTypes = classTypes;
var mappedTo = [];
this.mappedTo = mappedTo;
var self = this;
this["holder"] = null;
var IoC = function (type, parameters) {
var t = self.resolveType(type);
var inst = Object.create(t.prototype);
t.apply(inst, parameters);
return inst;
};
var pendingResolutions = {};
this.pendingResolutions = pendingResolutions;
function addPendingResolution(name, onResolved) {
pendingResolutions[name] = pendingResolutions[name] || [];
pendingResolutions[name].push(onResolved);
}
this.addChildContainer = function (container) {
//children.push(container);
}
this.createInstance = function (type, parameters) { return IoC(type, parameters); };
this.mapType = function (aliasTypeOrName, realTypeOrName) {
Guard.requireValue("aliasType", aliasTypeOrName);
Guard.requireValue("realType", realTypeOrName);
var aliasT = this.getType(aliasTypeOrName);
var realT = this.getType(realTypeOrName);
var aliasPos = classTypes.indexOf(aliasT);
var realPos = classTypes.indexOf(realT);
mappedTo[aliasPos] = realPos;
},
//this.resolve = function (type, parameters) {
// var classFunction = this.resolveType(type, parameters);
// return new classFunction(parameters);
//};
this.isPrimitiveType = function (type) {
var t = this.resolveType(type);
switch (true) {
case t === Number:
case t === String:
case t === Date:
case t === Boolean:
case t === Array:
case t === Object:
case t === $data.Number:
case t === $data.Integer:
case t === $data.Date:
case t === $data.String:
case t === $data.Boolean:
case t === $data.Array:
case t === $data.Object:
case t === $data.Guid:
case t === $data.Byte:
case t === $data.SByte:
case t === $data.Decimal:
case t === $data.Float:
case t === $data.Int16:
case t === $data.Int32:
case t === $data.Int64:
case t === $data.DateTimeOffset:
case t === $data.Time:
case t === $data.SimpleBase:
case t === $data.Geospatial:
case t === $data.GeographyBase:
case t === $data.GeographyPoint:
case t === $data.GeographyLineString:
case t === $data.GeographyPolygon:
case t === $data.GeographyMultiPoint:
case t === $data.GeographyMultiLineString:
case t === $data.GeographyMultiPolygon:
case t === $data.GeographyCollection:
case t === $data.GeometryBase:
case t === $data.GeometryPoint:
case t === $data.GeometryLineString:
case t === $data.GeometryPolygon:
case t === $data.GeometryMultiPoint:
case t === $data.GeometryMultiLineString:
case t === $data.GeometryMultiPolygon:
case t === $data.GeometryCollection:
return true;
default:
return false;
}
//return t === Number || t === String || t === Date || t === String || t === Boolean || t === Array || t === Object ||
// t === $data.Number || t === $data.Integer || t === $data.Date || t === $data.String || t === $data.Boolean || t === $data.Array || t === $data.Object ||
// t === $data.GeographyPoint || t === $data.Guid;
};
this.resolveName = function (type) {
var t = this.resolveType(type);
var tPos = classTypes.indexOf(t);
return consolidatedClassNames[tPos];
};
this.resolveType = function (typeOrName, onResolved) {
//if ("string" === typeof typeOrName) {
// console.log("@@@@String type!!!", typeOrName)
//}
var t = typeOrName;
t = this.getType(t, onResolved ? true : false, onResolved);
var posT = classTypes.indexOf(t);
return typeof mappedTo[posT] === 'undefined' ? t : classTypes[mappedTo[posT]];
};
this.getType = function (typeOrName, doNotThrow, onResolved) {
Guard.requireValue("typeOrName", typeOrName);
if (typeof typeOrName === 'function') {
return typeOrName;
};
if (!(typeOrName in classNames)) {
if (parent) {
var tp = parent.getType(typeOrName, true);
if (tp) return tp;
}
if (onResolved) {
addPendingResolution(typeOrName, onResolved);
return;
}
else if (doNotThrow) {
return undefined;
} else {
Guard.raise(new Exception("Unable to resolve type:" + typeOrName));
}
};
var result = classTypes[classNames[typeOrName]];
if (onResolved) {
onResolved(result);
}
return result;
};
this.getName = function (typeOrName) {
var t = this.getType(typeOrName);
var tPos = classTypes.indexOf(t);
if (tPos == -1)
Guard.raise("unknown type to request name for: " + typeOrName);
return consolidatedClassNames[tPos];
};
this.getTypes = function () {
var keys = Object.keys(classNames);
var ret = [];
for (var i = 0; i < keys.length; i++) {
var className = keys[i];
ret.push({ name: className, type: classTypes[classNames[className]], toString: function () { return this.name; } });
}
return ret;
};
//this.getTypeName( in type);
//this.resolveType()
//this.inferTypeFromValue = function (value) {
this.getTypeName = function (value) {
//TODO refactor
switch (typeof value) {
case 'object':
if (value == null) return '$data.Object';
if (value instanceof Array) return '$data.Array';
if (value.getType) return value.getType().fullName;
if (value instanceof Date) return '$data.Date';
if (value instanceof $data.Guid) return '$data.Guid';
if (value instanceof $data.DateTimeOffset) return '$data.DateTimeOffset';
if (value instanceof $data.GeographyPoint) return '$data.GeographyPoint';
if (value instanceof $data.GeographyLineString) return '$data.GeographyLineString';
if (value instanceof $data.GeographyPolygon) return '$data.GeographyPolygon';
if (value instanceof $data.GeographyMultiPoint) return '$data.GeographyMultiPoint';
if (value instanceof $data.GeographyMultiLineString) return '$data.GeographyMultiLineString';
if (value instanceof $data.GeographyMultiPolygon) return '$data.GeographyMultiPolygon';
if (value instanceof $data.GeographyCollection) return '$data.GeographyCollection';
if (value instanceof $data.GeographyBase) return '$data.GeographyBase';
if (value instanceof $data.GeometryPoint) return '$data.GeometryPoint';
if (value instanceof $data.GeometryLineString) return '$data.GeometryLineString';
if (value instanceof $data.GeometryPolygon) return '$data.GeometryPolygon';
if (value instanceof $data.GeometryMultiPoint) return '$data.GeometryMultiPoint';
if (value instanceof $data.GeometryMultiLineString) return '$data.GeometryMultiLineString';
if (value instanceof $data.GeometryMultiPolygon) return '$data.GeometryMultiPolygon';
if (value instanceof $data.GeometryCollection) return '$data.GeometryCollection';
if (value instanceof $data.GeometryBase) return '$data.GeometryBase';
if (value instanceof $data.Geospatial) return '$data.Geospatial';
if (value instanceof $data.SimpleBase) return '$data.SimpleBase';
if (typeof value.toHexString === 'function') return '$data.ObjectID';
//if(value instanceof "number") return
default:
return typeof value;
}
};
this.isTypeRegistered = function (typeOrName) {
if (typeof typeOrName === 'function') {
return classTypes.indexOf(typeOrName) > -1;
} else {
return typeOrName in classNames;
}
};
this.unregisterType = function (type) {
Guard.raise("Unimplemented");
};
this.getDefault = function (typeOrName) {
var t = this.resolveType(typeOrName);
switch (t) {
case $data.Number: return 0.0;
case $data.Float: return 0.0;
case $data.Decimal: return '0.0';
case $data.Integer: return 0;
case $data.Int16: return 0;
case $data.Int32: return 0;
case $data.Int64: return '0';
case $data.Byte: return 0;
case $data.SByte: return 0;
case $data.String: return null;
case $data.Boolean: return false;
default: return null;
}
};
//name array ['', '', '']
this.getIndex = function (typeOrName) {
var t = this.resolveType(typeOrName);
return classTypes.indexOf(t);
}
this.resolveByIndex = function (index) {
return classTypes[index];
}
this.registerType = function (nameOrNamesArray, type, factoryFunc) {
///<signature>
///<summary>Registers a type and optionally a lifetimeManager with a name
///that can be used to later resolve the type or create new instances</summary>
///<param name="nameOrNamesArray" type="Array">The names of the type</param>
///<param name="type" type="Function">The type to register</param>
///<param name="instanceManager" type="Function"></param>
///</signature>
///<signature>
///<summary>Registers a new type that </summary>
///<param name="aliasType" type="Function">The name of the type</param>
///<param name="actualType" type="Function">The type to register</param>
///</signature>
///TODO remove
/*if (typeof typeNameOrAlias === 'string') {
if (classNames.indexOf(typeNameOrAlias) > -1) {
Guard.raise("Type already registered. Remove first");
}
}*/
if (!nameOrNamesArray) {
return;
}
//todo add ('number', 'number')
if (typeof type === "string") {
type = self.resolveType(type);
}
var namesArray = [];
if (typeof nameOrNamesArray === 'string') {
var tmp = [];
tmp.push(nameOrNamesArray);
namesArray = tmp;
} else {
namesArray = nameOrNamesArray;
}
for (var i = 0; i < namesArray.length; i++) {
var parts = namesArray[i].split('.');
var item = {};
item.shortName = parts[parts.length - 1];
item.fullName = namesArray[i];
namesArray[i] = item;
}
//if (type.
var creatorFnc = function () { return IoC(type, arguments); };
if (typeof intellisense !== 'undefined') {
intellisense.annotate(creatorFnc, type);
}
for (var i = 0, l = namesArray.length; i < l; i++) {
var item = namesArray[i];
if (!(("create" + item.shortName) in self)) {
if (typeof factoryFunc === 'function') {
self["create" + item.shortName] = factoryFunc;
} else {
self["create" + item.shortName] = creatorFnc;
}
}
var typePos = classTypes.indexOf(type);
if (typePos == -1) {
//new type
typePos = classTypes.push(type) - 1;
var fn = item.fullName;
consolidatedClassNames[typePos] = item.fullName;
};
classNames[item.fullName] = typePos;
var pending = pendingResolutions[item.fullName] || [];
if (pending.length > 0) {
pending.forEach(function (t) {
t(type);
});
pendingResolutions[item.fullName] = [];
}
}
if (parent) {
parent.registerType.apply(parent, arguments);
}
if (!type.name) {
type.name = namesArray[0].shortName;
}
};
var _converters = {
from: {},
to: {}
};
this.converters = _converters;
this.convertTo = function (value, tType, eType /*if Array*/, options) {
Guard.requireValue("typeOrName", tType);
if(Object.isNullOrUndefined(value))
return value;
var sourceTypeName = Container.getTypeName(value);
var sourc