@@ -693,6 +693,86 @@ export class ExpressionFunctions {
693693 ( expr : Expression ) : void => ExpressionFunctions . validateArityAndAnyType ( expr , 2 , 3 , ReturnType . String , ReturnType . Number ) ) ;
694694 }
695695
696+ /**
697+ * Lookup a property in IDictionary, JObject or through reflection.
698+ * @param instance Instance with property.
699+ * @param property Property to lookup.
700+ * @returns Value and error information if any.
701+ */
702+ public static accessProperty ( instance : any , property : string ) : { value : any ; error : string } {
703+ // NOTE: This returns null rather than an error if property is not present
704+ if ( ! instance ) {
705+ return { value : undefined , error : undefined } ;
706+ }
707+
708+ let value : any ;
709+ let error : string ;
710+ // todo, Is there a better way to access value, or any case is not listed below?
711+ if ( instance instanceof Map && instance as Map < string , any > !== undefined ) {
712+ const instanceMap : Map < string , any > = instance as Map < string , any > ;
713+ value = instanceMap . get ( property ) ;
714+ if ( value === undefined ) {
715+ const prop : string = Array . from ( instanceMap . keys ( ) ) . find ( ( k : string ) : boolean => k . toLowerCase ( ) === property . toLowerCase ( ) ) ;
716+ if ( prop !== undefined ) {
717+ value = instanceMap . get ( prop ) ;
718+ }
719+ }
720+ } else {
721+ const prop : string = Object . keys ( instance ) . find ( ( k : string ) : boolean => k . toLowerCase ( ) === property . toLowerCase ( ) ) ;
722+ if ( prop !== undefined ) {
723+ value = instance [ prop ] ;
724+ }
725+ }
726+
727+ return { value, error } ;
728+ }
729+
730+ /**
731+ * Set a property in Map or Object.
732+ * @param instance Instance to set.
733+ * @param property Property to set.
734+ * @param value Value to set.
735+ * @returns set value.
736+ */
737+ public static setProperty ( instance : any , property : string , value : any ) : { value : any ; error : string } {
738+ const result : any = value ;
739+ if ( instance instanceof Map ) {
740+ instance . set ( property , value ) ;
741+ } else {
742+ instance [ property ] = value ;
743+ }
744+
745+ return { value : result , error : undefined } ;
746+ }
747+
748+ /**
749+ * Lookup a property in IDictionary, JObject or through reflection.
750+ * @param instance Instance with property.
751+ * @param property Property to lookup.
752+ * @returns Value and error information if any.
753+ */
754+ public static accessIndex ( instance : any , index : number ) : { value : any ; error : string } {
755+ // NOTE: This returns null rather than an error if property is not present
756+ if ( instance === null || instance === undefined ) {
757+ return { value : undefined , error : undefined } ;
758+ }
759+
760+ let value : any ;
761+ let error : string ;
762+
763+ if ( Array . isArray ( instance ) ) {
764+ if ( index >= 0 && index < instance . length ) {
765+ value = instance [ index ] ;
766+ } else {
767+ error = `${ index } is out of range for ${ instance } ` ;
768+ }
769+ } else {
770+ error = `${ instance } is not a collection.` ;
771+ }
772+
773+ return { value, error } ;
774+ }
775+
696776 private static parseTimestamp ( timeStamp : string , transform ?: ( arg0 : moment . Moment ) => any ) : { value : any ; error : string } {
697777 let value : any ;
698778 const error : string = this . verifyISOTimestamp ( timeStamp ) ;
@@ -937,9 +1017,9 @@ export class ExpressionFunctions {
9371017 ( { value : idxValue , error } = index . tryEvaluate ( state ) ) ;
9381018 if ( ! error ) {
9391019 if ( Number . isInteger ( idxValue ) ) {
940- ( { value, error } = Extensions . accessIndex ( inst , Number ( idxValue ) ) ) ;
1020+ ( { value, error } = ExpressionFunctions . accessIndex ( inst , Number ( idxValue ) ) ) ;
9411021 } else if ( typeof idxValue === 'string' ) {
942- ( { value, error } = Extensions . accessProperty ( inst , idxValue . toString ( ) ) ) ;
1022+ ( { value, error } = ExpressionFunctions . accessProperty ( inst , idxValue . toString ( ) ) ) ;
9431023 } else {
9441024 error = `Could not coerce ${ index } to an int or string.` ;
9451025 }
@@ -2074,7 +2154,7 @@ export class ExpressionFunctions {
20742154 found = ( args [ 0 ] as Map < string , any > ) . get ( args [ 1 ] ) !== undefined ;
20752155 } else if ( typeof args [ 1 ] === 'string' ) {
20762156 let value : any ;
2077- ( { value, error } = Extensions . accessProperty ( args [ 0 ] , args [ 1 ] ) ) ;
2157+ ( { value, error } = ExpressionFunctions . accessProperty ( args [ 0 ] , args [ 1 ] ) ) ;
20782158 found = ! error && value !== undefined ;
20792159 }
20802160 }
@@ -2874,7 +2954,7 @@ export class ExpressionFunctions {
28742954 }
28752955
28762956 if ( Array . isArray ( args [ 0 ] ) && args [ 0 ] . length > 0 ) {
2877- first = Extensions . accessIndex ( args [ 0 ] , 0 ) . value ;
2957+ first = ExpressionFunctions . accessIndex ( args [ 0 ] , 0 ) . value ;
28782958 }
28792959
28802960 return first ;
@@ -2891,7 +2971,7 @@ export class ExpressionFunctions {
28912971 }
28922972
28932973 if ( Array . isArray ( args [ 0 ] ) && args [ 0 ] . length > 0 ) {
2894- last = Extensions . accessIndex ( args [ 0 ] , args [ 0 ] . length - 1 ) . value ;
2974+ last = ExpressionFunctions . accessIndex ( args [ 0 ] , args [ 0 ] . length - 1 ) . value ;
28952975 }
28962976
28972977 return last ;
0 commit comments