import { InternetObjectValidationError , ErrorArgs , InternetObjectError } from '../errors/io-error' ; import ErrorCodes from '../errors/io-error-codes' ; import { ParserTreeValue , Node } from '../parser/index' ; import { Token } from '../parser' ; import { isNumber , isToken , isNode , isString } from '../utils/is' ; import MemberDef from './memberdef' ; import TypeDef from './typedef' ; import { doCommonTypeCheck } from './utils' ; import KeyValueCollection from '../header/index' ; const NUMBER_TYPES = [ 'number' , 'int' , 'int32' , 'int16' , 'byte' ] ; internal class NumberDef implements TypeDef { private _type : string ; private _validator : any ; constructor ( type = 'number' ) { this . _type = type ; this . _validator = _getValidator ( type ) ; } getType ( ) { return this . _type ; } parse ( data , memberDef , vars ? ) { return this . validate ( data , memberDef , vars ) ; } load ( data , memberDef ) { return this . validate ( data , memberDef ) ; } serialize = ( data , memberDef ) : string => { if ( NUMBER_TYPES . indexOf ( memberDef . type ) === - 1 ) { throw new InternetObjectError ( ErrorCodes . invalidType ) ; } return this . validate ( data , memberDef ) . toString ( ) ; } ; validate ( data , memberDef , vars ? ) { const node = isToken ( data ) ? data : undefined ; const value = node ? node . value : data ; return _validate ( this . _validator , memberDef , value , node , vars ) ; } } function _validate ( validator , memberDef , value , node ? , vars ? ) { if ( vars && isString ( value ) ) { const valueFound = vars . getV ( value ) ; value = valueFound !== undefined ? valueFound : value ; } const validatedData = doCommonTypeCheck ( memberDef , value , node ) ; if ( validatedData !== value || validatedData === undefined ) return validatedData ; if ( ! isNumber ( value ) ) { throw new InternetObjectValidationError ( ErrorCodes . invalidValue ) ; } else if ( isNaN ( Number ( value ) ) ) { throw new InternetObjectValidationError ( ErrorCodes . notANumber , `Invalid number encountered for ${ memberDef . path }` ) ; } validator ( memberDef , value , node ) ; if ( memberDef . min !== undefined ) { const min = memberDef . min ; if ( memberDef . min !== undefined && value < min ) { throw new InternetObjectValidationError ( ... _invlalidMin ( memberDef , value , node ) ) ; } } if ( memberDef . max !== undefined && value > memberDef . max ) { throw new InternetObjectValidationError ( ... _invlalidMax ( memberDef , value , node ) ) ; } return value ; } function _intValidator ( min , max , memberDef , value , node ? ) { if ( value % 1 !== 0 ) { throw new InternetObjectValidationError ( ... _notAnInt ( memberDef , value , node ) ) ; } if ( ( min !== - 1 && value < min ) || ( max !== - 1 && value > max ) ) { throw new InternetObjectValidationError ( ... _outOfRange ( memberDef , value , node ) ) ; } } function _getValidator ( type ) { switch ( type ) { case 'number' : { return ( memberDef , value , node ? ) => { if ( ! isNumber ( value ) && isNaN ( Number ( value ) ) ) { throw new InternetObjectValidationError ( ... _notANumber ( memberDef , value , node ) ) ; } } ; } case 'byte' : { const range = 2 ** 8 ; return _intValidator . bind ( null , - ( range / 2 ) , range / 2 - 1 ) ; } case 'int16' : { const range = 2 ** 16 ; return _intValidator . bind ( null , - ( range / 2 ) , range / 2 - 1 ) ; } case 'int32' : { const range = 2 ** 32 ; return _intValidator . bind ( null , - ( range / 2 ) , range / 2 - 1 ) ; } case 'int' : { return _intValidator . bind ( null , - 1 , - 1 ) ; } default : { console . assert ( false , 'Invalid number type!' ) ; } } } function _outOfRange ( memberDef , value , node ? ) { return [ ErrorCodes . outOfRange , `The value (${ value }) set for "${ memberDef . path }" is out of range.` , node ] ; } function _notAnInt ( memberDef , value , node ? ) { return [ ErrorCodes . notAnInteger , `Expecting an integer value for "${ memberDef . path }", Currently it is ${ value }.` , node ] ; } function _notANumber ( memberDef , value , node ? ) { return [ ErrorCodes . notANumber , `Expecting a number value for "${ memberDef . path }", Currently it is ${ value }.` , node ] ; } function _invlalidMin ( memberDef , value , node ? ) { return [ ErrorCodes . invalidMinValue , `The "${ memberDef . path }" must be greater than or equal to ${ memberDef . min }, Currently it is ${ value }.` , node ] ; } function _invlalidMax ( memberDef , value , node ? ) { return [ ErrorCodes . invalidMaxValue , `The "${ memberDef . path }" must be less than or equal to ${ memberDef . max }, Currently it is ${ value }.` , node ] ; } export default NumberDef ;