license import { Constructor } from './types' ; /**
 * A class that can observe targets and perform cleanup logic. Classes may
 * implement this using the `mdcObserver()` mixin.
 */ export interface MDCObserver { template T param target param observers return observe < T extends object > ( target , observers ) : ( ) => void ; param target param enabled setObserversEnabled ( target , enabled ) : void ; /**
     * Clean up all observers and stop listening for property changes.
     */ unobserve ( ) : void ; } template T template K template This param current param previous export type Observer < T extends object , K extends keyof T = keyof T , This = unknown > = ( this : This , current : T [ K ] , previous : T [ K ] ) => void ; template T template This export type ObserverRecord < T extends object , This = unknown > = { [ K in keyof T ] ? : Observer < T , K , This > ; } ; 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 unobserveMap = new WeakMap < MDCObserver , Function [ ] > ( ) ; return class MDCObserver extends baseClass implements MDCObserver { 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 unobserves = unobserveMap . get ( this ) || [ ] ; const index = unobserves . indexOf ( unobserve ) ; if ( index > - 1 ) { unobserves . splice ( index , 1 ) ; } } ; let unobserves = unobserveMap . get ( this ) ; if ( ! unobserves ) { unobserves = [ ] ; unobserveMap . set ( this , unobserves ) ; } unobserves . push ( unobserve ) ; return unobserve ; } setObserversEnabled ( target , enabled ) { setObserversEnabled ( target , enabled ) ; } unobserve ( ) { const unobserves = unobserveMap . get ( this ) || [ ] ; for ( const unobserve of [ ... unobserves ] ) { unobserve ( ) ; } } } ; } template T interface TargetObservers < T extends object > { /**
     * 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 ) : Array < Observer < T , K > > ; /**
     * A Set of properties that have been installed (their getter/setter) replaced
     * to connect with the `TargetObservers`. This prevents multiple installations
     * of the same property.
     */ installedProperties : Set < keyof T > ; } 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 targetObservers = installObserver ( target , property ) ; const observers = targetObservers . getObservers ( property ) ; observers . push ( observer ) ; return ( ) => { observers . splice ( observers . indexOf ( observer ) , 1 ) ; } ; } /**
 * A Map of all `TargetObservers` that have been installed.
 */ const allTargetObservers = new WeakMap < object , TargetObservers < any > > ( ) ; template T template K param target param property return function installObserver < T extends object , K extends keyof T > ( target , property ) { const observersMap = new Map < keyof T , Array < Observer < T > > > ( ) ; if ( ! allTargetObservers . has ( target ) ) { allTargetObservers . set ( target , { isEnabled : true , getObservers ( key ) { const observers = observersMap . get ( key ) || [ ] ; if ( ! observersMap . has ( key ) ) { observersMap . set ( key , observers ) ; } return observers ; } , installedProperties : new Set ( ) } as TargetObservers < T > ) ; } const targetObservers = allTargetObservers . get ( target ) ! ; if ( targetObservers . installedProperties . has ( property ) ) { return targetObservers ; } const descriptor = getDescriptor ( target , property ) || { configurable : true , enumerable : true , value : target [ property ] , writable : true } ; const observedDescriptor = { ... descriptor } ; let { get : descGet , set : descSet } = descriptor ; if ( 'value' in descriptor ) { delete observedDescriptor . value ; delete observedDescriptor . writable ; let value = descriptor . value as T [ K ] ; descGet = ( ) => value ; if ( descriptor . writable ) { descSet = ( newValue ) => { value = newValue ; } ; } } if ( descGet ) { observedDescriptor . get = function ( this ) { return descGet ! . call ( this as T ) ; } ; } if ( descSet ) { observedDescriptor . set = function ( this , newValue ) { const previous = descGet ? descGet . call ( this as T ) : newValue ; descSet ! . call ( this as T , newValue ) ; if ( targetObservers . isEnabled && ( ! descGet || newValue !== previous ) ) { for ( const observer of targetObservers . getObservers ( property ) ) { observer ( newValue , previous ) ; } } } ; } targetObservers . installedProperties . add ( property ) ; Object . defineProperty ( target , property , observedDescriptor ) ; return targetObservers ; } template T template K param target param property return export function getDescriptor < T extends object , K extends keyof T > ( target , property ) { let descriptorTarget = target ; let descriptor ; while ( descriptorTarget ) { descriptor = Object . getOwnPropertyDescriptor ( descriptorTarget , property ) ; if ( descriptor ) { break ; } descriptorTarget = Object . getPrototypeOf ( descriptorTarget ) ; } return descriptor ; } template T param target param enabled export function setObserversEnabled < T extends object > ( target , enabled ) { const targetObservers = allTargetObservers . get ( target ) ; if ( targetObservers ) { targetObservers . isEnabled = enabled ; } }