UNPKG

transactional

Version:

Reactive objects with transactional updates and automatic serialization

128 lines (95 loc) 3.66 kB
import { Attribute } from './attribute' class ConstructorType extends Attribute { type : new ( value : any ) => {} convert( value ) { return value == null || value instanceof this.type ? value : new this.type( value ); } clone( value, options ) { // delegate to clone function or deep clone through serialization return value.clone ? value.clone( value, options ) : this.convert( JSON.parse( JSON.stringify( value ) ) ); } } interface Function{ _attribute? : FunctionConstructor } Function.prototype[ '_attribute' ] = ConstructorType; // Date Attribute // ---------------------- class DateType extends Attribute { convert( value ) { return value == null || value instanceof Date ? value : new Date( typeof value === 'string' ? parseDate( value ) : value ); } validate( model, value, name ) { if( isNaN( +value ) ) return name + ' is Invalid Date'; } toJSON( value ) { return value && value.toJSON(); } isChanged( a, b ) { return ( a && +a ) !== ( b && +b ); } clone( value ) { return value && new Date( +value ); } } Date[ '_attribute' ] = DateType; // Primitive Types // ---------------- // Global Mock for missing Integer data type... // ------------------------------------- declare var Integer : any; Integer = function( x ) { return x ? Math.round( x ) : 0; }; class PrimitiveType extends Attribute { create() { return this.type(); } toJSON( value ) { return value; } convert( value ) { return value == null ? value : this.type( value ); } isChanged( a, b ) { return a !== b; } clone( value ) { return value; } } Boolean[ '_attribute' ] = String[ '_attribute' ] = PrimitiveType; class NumericType extends PrimitiveType { validate( model, value, name ) { if( !isFinite( value ) ) { return name + ' is invalid number'; } } } Integer[ '_attribute' ] = Number[ '_attribute' ] = NumericType; // Array Type // --------------- class ArrayType extends Attribute { toJSON( value ) { return value; } convert( value ) { // Fix incompatible constructor behaviour of Array... if( value == null || value instanceof Array ) return value; // todo: log an error. return []; } } Array[ '_attribute' ] = ArrayType; var numericKeys = [ 1, 4, 5, 6, 7, 10, 11 ], msDatePattern = /\/Date\(([0-9]+)\)\//, isoDatePattern = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/; function parseDate( date ) { var msDate, timestamp, struct, minutesOffset = 0; if( msDate = msDatePattern.exec( date ) ) { timestamp = Number( msDate[ 1 ] ); } else if( ( struct = isoDatePattern.exec( date )) ) { // avoid NaN timestamps caused by undefined values being passed to Date.UTC for( var i = 0, k; ( k = numericKeys[ i ] ); ++i ) { struct[ k ] = +struct[ k ] || 0; } // allow undefined days and months struct[ 2 ] = (+struct[ 2 ] || 1) - 1; struct[ 3 ] = +struct[ 3 ] || 1; if( struct[ 8 ] !== 'Z' && struct[ 9 ] !== undefined ) { minutesOffset = struct[ 10 ] * 60 + struct[ 11 ]; if( struct[ 9 ] === '+' ) { minutesOffset = 0 - minutesOffset; } } timestamp = Date.UTC( struct[ 1 ], struct[ 2 ], struct[ 3 ], struct[ 4 ], struct[ 5 ] + minutesOffset, struct[ 6 ], struct[ 7 ] ); } else { timestamp = Date.parse( date ); } return timestamp; }