import { PropertyFactory , BaseProperty , ContainerProperty , ValueProperty , SetProperty , MapProperty , ArrayProperty , } from "@fluid-experimental/property-properties" ; import { PathHelper } from "@fluid-experimental/property-changeset" ; import { arrayProxyHandler } from "./arrayProxyHandler" ; import { proxyHandler } from "./proxyHandler" ; import { ComponentArray } from "./componentArray" ; import { ComponentMap } from "./componentMap" ; import { ComponentSet } from "./componentSet" ; import { PropertyProxyErrors } from "./errors" ; import { IParentAndPathOfReferencedProperty } from "./IParentAndPathOfReferencedProperty" ; import { forceType } from "./utilities" ; import { ProxyType , PropertyTypes , ReferenceType } from "./interfaces" ; /**
 * This symbol is available on properties proxied via the PropertyProxy.[[proxify]] method.
 */ export const proxySymbol = Symbol ( "property-proxy" ) ; public export namespace PropertyProxy { param property param key public export function getParentOfReferencedProperty ( property , key ? ) { const keys = ( key === undefined ? [ ] : [ key ] ) ; const path = ( property . getValue as any ) ( ... keys ) ; const types = [ ] ; const tokens = PathHelper . tokenizePathString ( path , types ) ; let referencedPropertyParent ; let relativePathFromParent ; if ( ! PropertyFactory . instanceOf ( ( property . get as any ) ( ... keys ) , "BaseProperty" ) ) { if ( types . includes ( PathHelper . TOKEN_TYPES . ARRAY_TOKEN ) ) { relativePathFromParent = tokens . pop ( ) ; if ( tokens [ 0 ] === "/" ) { tokens . shift ( ) ; referencedPropertyParent = property . getRoot ( ) . get ( tokens ) ; } else { const parent = property . getParent ( ) as ContainerProperty ; if ( types . includes ( PathHelper . TOKEN_TYPES . RAISE_LEVEL_TOKEN ) ) { referencedPropertyParent = parent . resolvePath ( path . slice ( 0 , path . lastIndexOf ( "[" ) ) ) ; } else { referencedPropertyParent = parent . get ( tokens ) ; } } } else { const parent = property . getParent ( ) as ContainerProperty ; referencedPropertyParent = parent . resolvePath ( `${ path }*` ) ; relativePathFromParent = undefined ; } } else { const prop = ( property . get as any ) ( ... keys ) ! as BaseProperty ; referencedPropertyParent = prop . getParent ( ) ; relativePathFromParent = prop . getRelativePath ( referencedPropertyParent ) ; relativePathFromParent = PathHelper . tokenizePathString ( relativePathFromParent ) [ 0 ] ; } if ( PropertyFactory . instanceOf ( referencedPropertyParent , "Reference" ) || PropertyFactory . instanceOf ( referencedPropertyParent , "Reference" , "array" ) || PropertyFactory . instanceOf ( referencedPropertyParent , "Reference" , "map" ) ) { ( { referencedPropertyParent , relativePathFromParent } = getParentOfReferencedProperty ( referencedPropertyParent , relativePathFromParent ) ) ; } return { referencedPropertyParent , relativePathFromParent } ; } example param property public export function proxify < T extends PropertyTypes > ( property ) { if ( PropertyFactory . instanceOf ( property , "BaseProperty" ) ) { const context = property . getContext ( ) ; let proxy ; switch ( context ) { case "array" : proxy = new Proxy ( new ComponentArray ( property as ArrayProperty ) , arrayProxyHandler ) ; break ; case "map" : proxy = new ComponentMap ( property as MapProperty ) ; break ; case "set" : proxy = new ComponentSet ( property as SetProperty ) ; break ; default : if ( property . isPrimitiveType ( ) && forceType < ValueProperty > ( property ) ) { proxy = property . getValue ( ) ; } else { const target = { getProperty ( ) { if ( arguments . length > 0 ) { if ( Array . isArray ( arguments [ 0 ] ) && arguments [ 0 ] . length >= 2 && arguments [ 0 ] [ 1 ] !== BaseProperty . PATH_TOKENS . REF ) { throw new Error ( PropertyProxyErrors . DIRECT_CHILDREN_ONLY ) ; } return ( property as ContainerProperty ) . get ( ... arguments ) ; } return property ; } } ; proxy = new Proxy ( target , proxyHandler ) ; } break ; } if ( ! property . isPrimitiveType ( ) && ( context !== "single" ) ) { Object . defineProperty ( proxy , proxySymbol , { enumerable : false , configurable : true , writable : false , value : proxySymbol } ) ; } return proxy ; } else { throw new Error ( PropertyProxyErrors . INVALID_PROPERTY ) ; } } }