import { InvalidFormatError , isStackItemType , JSONHelper , PrimitiveStackItemJSON , StackItemJSON , StackItemType , } from '@neo-one/client-common' ; import { utils } from '@neo-one/utils' ; import { InvalidPrimitiveStackItemError , InvalidStackItemError , InvalidStackItemTypeError } from '../errors' ; import { ArrayStackItem } from './ArrayStackItem' ; import { BooleanStackItem } from './BooleanStackItem' ; import { BufferStackItem } from './BufferStackItem' ; import { ByteStringStackItem } from './ByteStringStackItem' ; import { IntegerStackItem } from './IntegerStackItem' ; import { InteropInterface } from './InteropInterface' ; import { MapStackItem } from './MapStackItem' ; import { NullStackItem } from './NullStackItem' ; import { PointerStackItem } from './PointerStackItem' ; import { StructStackItem } from './StructStackItem' ; export type PrimitiveStackItem = BooleanStackItem | IntegerStackItem | ByteStringStackItem ; export type StackItem = ArrayStackItem | BufferStackItem | InteropInterface | MapStackItem | NullStackItem | PointerStackItem | StructStackItem | PrimitiveStackItem ; export const isStackItem = ( item ) : item is StackItem => { if ( item !== undefined && item . type !== undefined && isStackItemType ( item . type ) ) { return StackItemType [ item . type ] !== undefined ; } return false ; } ; export const assertStackItem = ( item ) : StackItem => { if ( isStackItem ( item ) ) { return item ; } throw new InvalidStackItemError ( ) ; } ; export const getIsStackItemType = < T > ( type ) => ( item ) : item is T => { if ( isStackItem ( item ) ) { return item . type === type ; } return false ; } ; export const getAssertStackItemType = < T > ( isFunc , type ) => ( item ) => { if ( isFunc ( item ) ) { return item ; } throw new InvalidStackItemTypeError ( StackItemType [ type ] , item . type ) ; } ; export const isNullStackItem = getIsStackItemType ( StackItemType . Any ) ; export const isPointerStackItem = getIsStackItemType ( StackItemType . Pointer ) ; export const isBooleanStackItem = getIsStackItemType ( StackItemType . Boolean ) ; export const isIntegerStackItem = getIsStackItemType ( StackItemType . Integer ) ; export const isByteStringStackItem = getIsStackItemType ( StackItemType . ByteString ) ; export const isBufferStackItem = getIsStackItemType ( StackItemType . Buffer ) ; export const isArrayStackItem = getIsStackItemType ( StackItemType . Array ) ; export const isStructStackItem = getIsStackItemType ( StackItemType . Struct ) ; export const isMapStackItem = getIsStackItemType ( StackItemType . Map ) ; export const isInteropInterface = getIsStackItemType ( StackItemType . InteropInterface ) ; export const isArrayLikeStackItem = ( item ) : item is ArrayStackItem | StructStackItem => isArrayStackItem ( item ) || isStructStackItem ( item ) ; export const isPrimitiveStackItem = ( item ) : item is PrimitiveStackItem => isBooleanStackItem ( item ) || isByteStringStackItem ( item ) || isIntegerStackItem ( item ) ; export const assertAnyStackItem = getAssertStackItemType ( isNullStackItem , StackItemType . Any ) ; export const assertPointerStackItem = getAssertStackItemType ( isPointerStackItem , StackItemType . Pointer ) ; export const assertBooleanStackItem = getAssertStackItemType ( isBooleanStackItem , StackItemType . Boolean ) ; export const assertIntegerStackItem = getAssertStackItemType ( isIntegerStackItem , StackItemType . Integer ) ; export const assertByteStringStackItem = getAssertStackItemType ( isByteStringStackItem , StackItemType . ByteString ) ; export const assertBufferStackItem = getAssertStackItemType ( isBufferStackItem , StackItemType . Buffer ) ; export const assertArrayStackItem = getAssertStackItemType ( isArrayStackItem , StackItemType . Array ) ; export const assertStructStackItem = getAssertStackItemType ( isStructStackItem , StackItemType . Struct ) ; export const assertArrayLikeStackItem = ( item ) => { if ( isArrayLikeStackItem ( item ) ) { return item ; } throw new InvalidStackItemTypeError ( 'ArrayLikeStackItem' , item . type ) ; } ; export const assertMapStackItem = getAssertStackItemType ( isMapStackItem , StackItemType . Map ) ; export const assertInteropInterfaceStackItem = getAssertStackItemType ( isInteropInterface , StackItemType . InteropInterface ) ; export const assertPrimitiveStackItem = ( item ) : PrimitiveStackItem => { if ( isPrimitiveStackItem ( item ) ) { return item ; } throw new InvalidPrimitiveStackItemError ( ) ; } ; export const stackItemToJSON = ( item , context ? ) : StackItemJSON => { switch ( item . type ) { case StackItemType . Array : const array = assertArrayStackItem ( item ) ; const arrayContext = context ?? new Set < StackItem > ( ) ; if ( arrayContext . has ( array ) ) { throw new InvalidFormatError ( ) ; } arrayContext . add ( array ) ; return { type : 'Array' , value : array . array . map ( ( subItem ) => stackItemToJSON ( subItem , arrayContext ) ) } ; case StackItemType . Boolean : const booleanItem = assertBooleanStackItem ( item ) ; return { type : 'Boolean' , value : booleanItem . getBoolean ( ) } ; case StackItemType . Buffer : const buffer = assertBufferStackItem ( item ) ; return { type : 'Buffer' , value : JSONHelper . writeBase64Buffer ( buffer . getBuffer ( ) ) } ; case StackItemType . ByteString : const byteString = assertByteStringStackItem ( item ) ; return { type : 'ByteString' , value : byteString . getBuffer ( ) . toString ( 'base64' ) } ; case StackItemType . Integer : const integer = assertIntegerStackItem ( item ) ; return { type : 'Integer' , value : integer . getInteger ( ) . toString ( ) } ; case StackItemType . Map : const map = assertMapStackItem ( item ) ; const mapContext = context ?? new Set < StackItem > ( ) ; if ( mapContext . has ( map ) ) { throw new InvalidFormatError ( ) ; } mapContext . add ( map ) ; return { type : 'Map' , value : Array . from ( map . dictionary . entries ( ) ) . map ( ( [ key , value ] ) => ( { key : stackItemToJSON ( key , mapContext ) as PrimitiveStackItemJSON , value : stackItemToJSON ( value , mapContext ) } ) ) } ; case StackItemType . Pointer : const pointer = assertPointerStackItem ( item ) ; return { type : 'Pointer' , value : pointer . position } ; case StackItemType . Struct : return { type : 'Any' , value : undefined } ; case StackItemType . InteropInterface : return { type : 'Any' , value : undefined } ; case StackItemType . Any : return { type : 'Any' , value : undefined } ; default : utils . assertNever ( item . type ) ; throw new Error ( 'For TS' ) ; } } ;