import { ComponentTag } from './componentHelper' ; import { RequestInvalidError } from './requestProcessor' ; import * as _ from 'lodash' ; import { VM } from 'vm2' ; import { transformSync } from '@babel/core' ; import * as elvis from '@babel/plugin-proposal-optional-chaining' ; export interface InputValuesMap { [ fqtag ] : { [ inputName ] : any ; } ; } export interface TxContext { [ fieldName ] : any ; } export class TxInputsValidator { private static Eval ( unparsedExpr , context ) { const polyfilledCode = transformSync ( `(${ unparsedExpr })` , { plugins : [ elvis ] } ) . code ; console . log ( `Running code "${ polyfilledCode }" (pollyfilled from "${ unparsedExpr }") ` + `with context ${ JSON . stringify ( context ) }` ) ; const vm = new VM ( ) ; _ . forEach ( context , ( value , key ) => { vm . freeze ( value , key ) ; } ) ; while ( true ) { try { return vm . run ( polyfilledCode ) ; } catch ( e ) { const m = e . message . match ( /(.*) is not defined/ ) ; if ( m ) { console . log ( `Adding ${ m [ 1 ] } to context with value undefined` ) ; vm . freeze ( undefined , m [ 1 ] ) ; continue ; } throw e ; } } } public static Validate ( inputValues , txComponents , context ) { const components = { } ; for ( const txComponent of txComponents ) { _ . forEach ( txComponent . inputs , ( unparsedExpr , input ) => { const inputName = input . startsWith ( '[' ) ? input . slice ( 1 , - 1 ) : input ; _ . set ( components , [ txComponent . fqtag , inputName ] , unparsedExpr ) ; } ) ; } _ . forEach ( inputValues , ( input , componentFqTag ) => { _ . forEach ( input , ( inputValue , inputName ) => { TxInputsValidator . ValidateInput ( componentFqTag , inputName , inputValue , context , components ) ; } ) ; } ) ; } private static ValidateInput ( fqtag , inputName , inputValue , context , components ) { const unparsedExpr = _ . get ( components , [ fqtag , inputName ] ) ; if ( unparsedExpr === undefined ) { console . log ( `Not checking ${ fqtag }.${ inputName } since it's an internal input` ) ; return ; } console . log ( `Checking ${ fqtag }.${ inputName }: ${ inputValue }` ) ; const expectedValue = TxInputsValidator . Eval ( unparsedExpr , context ) ; console . log ( `Expected value for ${ fqtag }.${ inputName } is ${ expectedValue }` ) ; if ( ! _ . isEqual ( expectedValue , inputValue ) ) { throw new RequestInvalidError ( `The value obtained for ${ fqtag }.${ inputName } is not the expected ` + `one (${ inputValue } is not equal to ${ expectedValue })` ) ; } } }