Created
June 24, 2014 17:15
-
-
Save xperiments/d5420a55a1eb7ed407c1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module io.xperiments.utils.serialize | |
{ | |
/** | |
* The mini | |
*/ | |
export interface ISerializableObject | |
{ | |
"@serializable":string; | |
} | |
export interface ISerializable extends ISerializableObject | |
{ | |
"@serializable":string; | |
writeObject( root:boolean ):any; | |
readObject( obj:any ):void; | |
} | |
export class Serializable implements ISerializable | |
{ | |
public "@serializable":string; | |
/** | |
* | |
* @returns {any} | |
*/ | |
public writeObject():any | |
{ | |
return Serializer.writeObject( this ); | |
} | |
/** | |
* | |
* @param obj | |
*/ | |
public readObject(obj:any):void | |
{ | |
Serializer.readObject(this, obj); | |
} | |
} | |
export interface ISerializableRegisters | |
{ | |
[key:string]:ISerializableRegister; | |
} | |
export interface ISerializableRegister | |
{ | |
keys:string[]; | |
serializerData:any; | |
} | |
export class Serializer | |
{ | |
private static serializableRegisters:ISerializableRegisters = {}; | |
/** | |
* | |
* @param classContext | |
* @param SerializerDataClass | |
*/ | |
public static registerClass( classContext:()=>any, SerializerDataClass:any ):void | |
{ | |
// determine class global path by parsing the body of the classContext Function | |
var classPath:string = /return ([A-Za-z0-9_$]*)/g.exec(classContext.toString())[1]; | |
// Check if class has been processed | |
if( Serializer.serializableRegisters[ classPath ] ) | |
{ | |
throw new Error('Class '+classPath+' already registered'); | |
} | |
Serializer.getClassFromPath( classPath ).prototype['@serializable'] = classPath; | |
Serializer.serializableRegisters[classPath] = | |
{ | |
keys:Serializer.getMixedNames( SerializerDataClass ), | |
serializerData:SerializerDataClass | |
}; | |
} | |
/** | |
* | |
* @param instance | |
* @returns {any} | |
*/ | |
public static writeObject( instance:ISerializable ):any | |
{ | |
var obj:any = {}; | |
var register:ISerializableRegister = Serializer.getSerializableRegister( instance ); | |
register.keys.filter((key)=>{ return key.indexOf('set_')!=0 && key.indexOf('get_')!=0 }).forEach(( key:string )=> | |
{ | |
var value:any = instance[key]; | |
if( !value ) return; // don't getSerializableProperties void/empty/undefined | |
Serializer.writeAny( value, key, obj, register.serializerData ); | |
}); | |
return obj; | |
} | |
/** | |
* | |
* @param instance | |
* @param obj | |
*/ | |
public static readObject( instance:ISerializable, obj:any ):void | |
{ | |
var register:ISerializableRegister = Serializer.getSerializableRegister( instance ); | |
Serializer.getSerializableRegister( instance ).keys | |
.forEach( ( key:string )=> Serializer.readAny( obj[key], key, instance, register.serializerData ) ); | |
} | |
// Private Methods | |
/** | |
* | |
* @param array | |
* @returns {any[]} | |
*/ | |
private static writeArray( array:any[] ):any[] | |
{ | |
var returnArray:any[] = []; | |
array.forEach( ( element , i )=> Serializer.writeAny( element,i,returnArray , Serializer.getSerializableRegister( element[i] ).serializerData) ); | |
return returnArray; | |
} | |
/** | |
* | |
* @param element | |
* @param key | |
* @param target | |
* @param SerializerDataClass | |
*/ | |
private static writeAny( element:any,key:any,target:any, SerializerDataClass:any ) | |
{ | |
if( typeof SerializerDataClass.prototype["set_"+key] == "function" ) | |
{ | |
target[key] = SerializerDataClass.prototype["set_"+key]( element ); | |
return; | |
} | |
var elementType = typeof element; | |
switch( true ) | |
{ | |
case elementType=="boolean": | |
case elementType=="string": | |
case elementType=="number": | |
target[key] = element; | |
break; | |
case Array.isArray( element ): | |
target[key] = Serializer.writeArray( element ); | |
break; | |
case elementType=="object" && !Array.isArray( element ): | |
console.log( element instanceof Date,'0000') | |
target[key] = Serializer.isExternalizable( element ) ? Serializer.writeObject( element ):JSON.parse(JSON.stringify( element )); | |
break; | |
} | |
} | |
/** | |
* | |
* @param array | |
* @returns {any[]} | |
*/ | |
private static readArray( array:any[] ):any[] | |
{ | |
var resultArray:any[] = []; | |
array.forEach( ( element, i )=>Serializer.readAny( element, i, resultArray, Serializer.getSerializableRegister( element[i] ).serializerData)); | |
return resultArray; | |
} | |
/** | |
* | |
* @param element | |
* @param key | |
* @param target | |
* @param SerializerDataClass | |
*/ | |
private static readAny( element:any, key:any, target:any, SerializerDataClass:any ) | |
{ | |
if( typeof SerializerDataClass.prototype["get_"+key] == "function" ) | |
{ | |
target[key] = SerializerDataClass.prototype["get_"+key]( element ); | |
return; | |
} | |
var type:string = typeof element; | |
switch( true ) | |
{ | |
case type=="boolean": | |
case type=="string": | |
case type=="number": | |
target[key] = element; | |
break; | |
case Array.isArray( element ): | |
target[key] = Serializer.readArray( element ); | |
break; | |
case type=="object" && !Array.isArray( element ): | |
if( element.hasOwnProperty('@serializable') ) | |
{ | |
var moduleParts:string[] = element['@serializable'].split('.'); | |
var classPath:string = moduleParts.join('.'); | |
if( !target[key] ) target[key] = Serializer.getClass(classPath); | |
target[key].readObject( element ); | |
} | |
else | |
{ | |
target[key] = element; | |
} | |
break; | |
} | |
} | |
/* Helper Methods */ | |
/** | |
* | |
* @param SerializerDataClass | |
* @returns {string[]} | |
*/ | |
private static getMixedNames( SerializerDataClass:any ):string[] | |
{ | |
return Object.getOwnPropertyNames( new SerializerDataClass() )//.concat( Object.keys( SerializerDataClass.prototype )); | |
} | |
/** | |
* | |
* @param instance | |
* @returns {boolean} | |
*/ | |
private static isExternalizable( instance ):boolean | |
{ | |
return '@serializable' in instance && typeof instance.writeObject == "function" && typeof instance.readObject == "function"; | |
} | |
/** | |
* | |
* @param name | |
* @param context | |
* @returns {any} | |
*/ | |
private static getClassFromPath( name:string , context:any = window ):any | |
{ | |
name.split('.').forEach( ctx=>context = context[ ctx ] ); | |
return context; | |
} | |
/** | |
* | |
* @param name | |
* @param context | |
* @returns {any} | |
*/ | |
private static getClass( name:string , context:any = window ):any | |
{ | |
name.split('.').forEach( ctx=>context = context[ ctx ] ); | |
return new context; | |
} | |
/** | |
* | |
* @param instance | |
* @returns {ISerializableRegister} | |
*/ | |
private static getSerializableRegister( instance:ISerializable ):ISerializableRegister | |
{ | |
var props:ISerializableRegister = Serializer.serializableRegisters[ instance['@serializable'] ]; | |
if(!props) | |
{ | |
throw new Error('Unable to get serializable properties for class '+instance['@serializable'] ) | |
} | |
return props; | |
} | |
} | |
} | |
/* Simple TEST */ | |
import ISerializableObject = io.xperiments.utils.serialize.ISerializableObject; | |
import Serializer = io.xperiments.utils.serialize.Serializer; | |
import Serializable = io.xperiments.utils.serialize.Serializable; | |
// the actual real class | |
class Data extends Serializable | |
{ | |
"@serializable":string; | |
name:string; | |
address:string; | |
date:Date; | |
constructor() | |
{ | |
super(); | |
this.name = "foo"; | |
this.address = "address"; | |
this.date = new Date(); | |
this.date.setMonth(1) | |
} | |
} | |
// here our values pattern to export | |
class DataSerializer implements ISerializableObject | |
{ | |
"@serializable":string = null; | |
name:string = null; | |
date:string = null; | |
set_date(date:Date):string{return [ date.getFullYear(), date.getMonth()+1, date.getDate()].join('/')} | |
get_date(dateString:string):Date | |
{ | |
var dateParts:string[] = dateString.split('/'); | |
var date = new Date(); | |
date.setFullYear( parseInt(dateParts[0],10)); | |
date.setMonth( parseInt(dateParts[1],10)-1); | |
date.setDate( parseInt(dateParts[2],10)); | |
return date; | |
} | |
} | |
Serializer.registerClass( ()=>Data, DataSerializer ); | |
class ISubData implements ISerializableObject | |
{ | |
"@serializable":string = null; | |
data:Data = null; | |
name:string = null; | |
date:string = null; | |
image:HTMLImageElement = null; | |
set_image( image:HTMLImageElement ):string | |
{ | |
var canvas:HTMLCanvasElement = document.createElement('canvas'); | |
canvas.width = image.width; | |
canvas.height = image.height; | |
canvas.getContext('2d').drawImage( image,0,0 ); | |
return canvas.toDataURL(); | |
} | |
get_image( image64:string ):HTMLImageElement | |
{ | |
var img:HTMLImageElement = document.createElement('img'); | |
img.src = image64; | |
return img; | |
} | |
set_date(date:Date):string{console.log('paso write');return [ date.getFullYear(), date.getMonth()+1, date.getDate()].join('/')} | |
get_date(dateString:string):Date | |
{ | |
console.log('paso read'); | |
var dateParts:string[] = dateString.split('/'); | |
var date = new Date(); | |
date.setFullYear( parseInt(dateParts[0],10)); | |
date.setMonth( parseInt(dateParts[1],10)-1); | |
date.setDate( parseInt(dateParts[2],10)); | |
return date; | |
} | |
} | |
// the actual real class | |
class SubData extends Serializable implements ISerializableObject | |
{ | |
"@serializable":string; | |
data:Data; | |
name:string = "PEDRO"; | |
date:Date = new Date(); | |
image:HTMLImageElement; | |
constructor() | |
{ | |
super(); | |
this.data = new Data(); | |
this.data.name = "SOME OTHER VALUE"; | |
this.name = "JUAN"; | |
this.data.address="SAMANIEGO 67"; | |
this.image = document.createElement('img'); | |
} | |
} | |
Serializer.registerClass( ()=>SubData, ISubData ); | |
var c = new SubData(); | |
c.name="NEW VALUE"; | |
/* ATTENTION CHANGE IMAGE HERE */ | |
c.image.src = "iphone-6-concept-Copiar.jpg"; | |
setTimeout(()=>{ | |
var d = new SubData(); | |
d.readObject( c.writeObject() ); | |
document.body.appendChild( d.image ) | |
},5000); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment