license import { getDescriptor , MDCObserver , Observer , ObserverRecord } from './observer' ; import { Constructor } from './types' ; deprecated return export function mdcObserver ( ) ; deprecated template T template C param baseClass return export function mdcObserver < T , C extends Constructor < T > > ( baseClass ) ; deprecated template C param baseClass return export function mdcObserver < C extends Constructor > ( baseClass = class { } as C ) { const unobserves = Symbol ( ) ; return class MDCObserver extends baseClass implements MDCObserver { [ unobserves ] : Function [ ] = [ ] ; observe < T extends object > ( target , observers ) { const cleanup = [ ] ; for ( const property of Object . keys ( observers ) as Array < keyof T > ) { const observer = observers [ property ] ! . bind ( this ) ; cleanup . push ( observeProperty ( target , property , observer ) ) ; } const unobserve = ( ) => { for ( const cleanupFn of cleanup ) { cleanupFn ( ) ; } const index = this [ unobserves ] . indexOf ( unobserve ) ; if ( index > - 1 ) { this [ unobserves ] . splice ( index , 1 ) ; } } ; this [ unobserves ] . push ( unobserve ) ; return unobserve ; } setObserversEnabled ( target , enabled ) { setObserversEnabled ( target , enabled ) ; } unobserve ( ) { for ( const unobserve of [ ... this [ unobserves ] ] ) { unobserve ( ) ; } } } ; } const isTargetObservers = Symbol ( ) ; const isEnabled = Symbol ( ) ; const getObservers = Symbol ( ) ; template T interface TargetObservers < T extends object > { /**
     * Indicates that the prototype is a `TargetObservers` instance.
     */ [ isTargetObservers ] : true ; /**
     * Indicates whether or not observers for this target are enabled. If
     * disabled, observers will not be called in response to target property
     * changes.
     */ [ isEnabled ] : boolean ; template K param key return [ getObservers ] : < K extends keyof T > ( key : K ) => Array < Observer < T , K > > ; } template T template K param target param property param observer return export function observeProperty < T extends object , K extends keyof T > ( target , property , observer ) { const observerPrototype = installObserver ( target ) ; const observers = observerPrototype [ getObservers ] ( property ) ; observers . push ( observer ) ; return ( ) => { observers . splice ( observers . indexOf ( observer ) , 1 ) ; } ; } template T param target return function installObserver < T extends object > ( target ) { const prototype = Object . getPrototypeOf ( target ) ; if ( prototype [ isTargetObservers ] ) { return prototype as TargetObservers < T > ; } const existingKeyValues = new Map < keyof T , T [ keyof T ] > ( ) ; const keys = Object . getOwnPropertyNames ( target ) as Array < keyof T > ; for ( const key of keys ) { const descriptor = getDescriptor ( target , key ) ; if ( descriptor && descriptor . writable ) { existingKeyValues . set ( key , descriptor . value as T [ keyof T ] ) ; delete target [ key ] ; } } const proxy = new Proxy < T > ( Object . create ( prototype ) , { get ( target , key , receiver ) { return Reflect . get ( target , key , receiver ) ; } , set ( target , key , newValue , receiver ) { const isTargetObserversKey = key === isTargetObservers || key === isEnabled || key === getObservers ; const previous = Reflect . get ( target , key , receiver ) ; Reflect . set ( target , key , newValue ) ; if ( ! isTargetObserversKey && proxy [ isEnabled ] && newValue !== previous ) { for ( const observer of proxy [ getObservers ] ( key as keyof T ) ) { observer ( newValue , previous ) ; } } return true ; } } ) as TargetObservers < T > ; proxy [ isTargetObservers ] = true ; proxy [ isEnabled ] = true ; const observersMap = new Map < keyof T , Array < Observer < T > > > ( ) ; proxy [ getObservers ] = ( key ) => { const observers = observersMap . get ( key ) || [ ] ; if ( ! observersMap . has ( key ) ) { observersMap . set ( key , observers ) ; } return observers ; } ; Object . setPrototypeOf ( target , proxy ) ; for ( const [ key , value ] of existingKeyValues . entries ( ) ) { target [ key ] = value ; } return proxy ; } template T param target param enabled export function setObserversEnabled < T extends object > ( target , enabled ) { const prototype = Object . getPrototypeOf ( target ) ; if ( prototype [ isTargetObservers ] ) { ( prototype as TargetObservers < T > ) [ isEnabled ] = enabled ; } }