import { Context , DevtoolsPluginApi , Hookable } from './api' ; import { PluginDescriptor } from './plugin' ; import { HOOK_PLUGIN_SETTINGS_SET } from './const' ; interface QueueItem { method : string ; args : any [ ] ; resolve ? : ( value ? : any ) => void ; } export class ApiProxy < TTarget extends DevtoolsPluginApi < any > = DevtoolsPluginApi < any > > { target : TTarget | null ; targetQueue : QueueItem [ ] ; proxiedTarget : TTarget ; onQueue : QueueItem [ ] ; proxiedOn : Hookable < Context > ; plugin : PluginDescriptor ; hook : any ; fallbacks : Record < string , any > ; constructor ( plugin , hook ) { this . target = null ; this . targetQueue = [ ] ; this . onQueue = [ ] ; this . plugin = plugin ; this . hook = hook ; const defaultSettings = { } ; if ( plugin . settings ) { for ( const id in plugin . settings ) { const item = plugin . settings [ id ] ; defaultSettings [ id ] = item . defaultValue ; } } const localSettingsSaveId = `__vue-devtools-plugin-settings__${ plugin . id }` ; let currentSettings = Object . assign ( { } , defaultSettings ) ; try { const raw = localStorage . getItem ( localSettingsSaveId ) ; const data = JSON . parse ( raw ) ; Object . assign ( currentSettings , data ) ; } catch ( e ) { } this . fallbacks = { getSettings ( ) { return currentSettings ; } , setSettings ( value ) { try { localStorage . setItem ( localSettingsSaveId , JSON . stringify ( value ) ) ; } catch ( e ) { } currentSettings = value ; } , } ; if ( hook ) { hook . on ( HOOK_PLUGIN_SETTINGS_SET , ( pluginId , value ) => { if ( pluginId === this . plugin . id ) { this . fallbacks . setSettings ( value ) ; } } ) ; } this . proxiedOn = new Proxy ( { } as Hookable < Context > , { get : ( _target , prop ) => { if ( this . target ) { return this . target . on [ prop ] ; } else { return ( ... args ) => { this . onQueue . push ( { method : prop , args , } ) ; } ; } } , } ) ; this . proxiedTarget = new Proxy ( { } as TTarget , { get : ( _target , prop ) => { if ( this . target ) { return this . target [ prop ] ; } else if ( prop === 'on' ) { return this . proxiedOn ; } else if ( Object . keys ( this . fallbacks ) . includes ( prop ) ) { return ( ... args ) => { this . targetQueue . push ( { method : prop , args , resolve : ( ) => { } , } ) ; return this . fallbacks [ prop ] ( ... args ) ; } ; } else { return ( ... args ) => { return new Promise ( resolve => { this . targetQueue . push ( { method : prop , args , resolve , } ) ; } ) ; } ; } } , } ) ; } async setRealTarget ( target ) { this . target = target ; for ( const item of this . onQueue ) { this . target . on [ item . method ] ( ... item . args ) ; } for ( const item of this . targetQueue ) { item . resolve ( await this . target [ item . method ] ( ... item . args ) ) ; } } }