import { Disposable } from 'vscode' ; import _ from 'lodash' ; import { uniq } from '@antfu/utils' ; import { PendingWrite } from '../types' ; import { Translator } from '../Translator' ; import { Config } from '../Config' ; import { FulfillAllMissingKeys } from '../../commands/manipulations' ; import { LocaleTree , LocaleNode , FlattenLocaleTree } from '../Nodes' ; import { Loader } from './Loader' ; import { Log } from '~/utils' ; export class ComposedLoader extends Loader { constructor ( ) { super ( '[Composed]' ) ; this . _disposables . push ( Translator . onDidChange ( ( ) => this . _onDidChange . fire ( '' ) ) ) ; } _loaders : Loader [ ] = [ ] ; _watchers : Disposable [ ] = [ ] ; _isFlattenLocaleTreeDirty = true ; get files ( ) { return _ . flatten ( this . _loaders . map ( l => l && l . files ) . filter ( Boolean ) ) ; } get loaders ( ) { return this . _loaders ; } set loaders ( value ) { this . _watchers . forEach ( d => d . dispose ( ) ) ; this . _loaders = value ; this . _watchers = this . loaders . filter ( i => i ) . map ( loader => loader . onDidChange ( ( e ) => { this . _isFlattenLocaleTreeDirty = true ; this . _onDidChange . fire ( `${ e }+${ this . name }` ) ; } ) ) ; this . _isFlattenLocaleTreeDirty = true ; } get loadersReversed ( ) { return this . _loaders . slice ( ) . reverse ( ) ; } get root ( ) : LocaleTree { const children = { } ; for ( const loader of this . _loaders ) { const loaderChildren = loader . root . children ; for ( const key of Object . keys ( loaderChildren ) ) children [ key ] = loaderChildren [ key ] ; } return new LocaleTree ( { keypath : '' , children } ) ; } get flattenLocaleTree ( ) : FlattenLocaleTree { if ( ! this . _isFlattenLocaleTreeDirty ) return this . _flattenLocaleTree ; this . _flattenLocaleTree = { } ; for ( const loader of this . _loaders ) { const loaderChildren = loader ?. flattenLocaleTree ; if ( loaderChildren ) Object . assign ( this . _flattenLocaleTree , loaderChildren ) ; } this . _isFlattenLocaleTreeDirty = false ; return this . _flattenLocaleTree ; } get locales ( ) : string [ ] { return _ ( this . _loaders ) . flatMap ( l => l . locales ) . uniq ( ) . value ( ) ; } getNamespaceFromFilepath ( filepath ) { for ( const loader of this . loadersReversed ) { const value = loader . getNamespaceFromFilepath ( filepath ) ; if ( value ) return value ; } } getTreeNodeByKey ( keypath , tree ? ) { for ( const loader of this . loadersReversed ) { const value = loader . getTreeNodeByKey ( keypath , tree ) ; if ( value ) return value ; } } getFilepathByKey ( keypath , locale ? ) { for ( const loader of this . loadersReversed ) { const value = loader . getFilepathByKey ( keypath , locale ) ; if ( value ) return value ; } } getValueByKey ( keypath , locale ? , maxLength = 0 , stringifySpace ? ) { for ( const loader of this . loadersReversed ) { const value = loader . getValueByKey ( keypath , locale , maxLength , stringifySpace ) ; if ( value ) return value ; } } fire ( src ? ) { this . _onDidChange . fire ( src || this . name ) ; } async write ( pendings , triggerFullfilled = true ) { if ( ! Array . isArray ( pendings ) ) pendings = [ pendings ] ; if ( Config . keepFulfilled && triggerFullfilled ) { pendings = [ ... await FulfillAllMissingKeys ( false , uniq ( pendings . map ( i => i . keypath ) ) ) || [ ] , ... pendings , ] ; } pendings = pendings . filter ( i => i ) ; const distrubtedPendings = new Array ( this . loadersReversed . length ) . fill ( null ) . map ( ( ) => [ ] ) ; const loaders = this . loadersReversed ; for ( const pending of pendings ) { let handled = false ; loaders . forEach ( ( loader , index ) => { if ( handled ) return ; if ( loader . canHandleWrites ( pending ) ) { distrubtedPendings [ index ] . push ( pending ) ; handled = true ; } } ) ; if ( ! handled ) Log . info ( `💥 Unhandled write ${ JSON . stringify ( pending ) }` ) ; } await Promise . all ( loaders . map ( async ( loader , index ) => { if ( distrubtedPendings [ index ] && distrubtedPendings [ index ] . length ) await loader . write ( distrubtedPendings [ index ] ) ; } ) ) ; } }