import * as fs from 'fs' ; import * as path from 'path' ; import { updateYamlDocument } from '@atomist/yaml-updater' ; import { customRef , effect } from '@vue/reactivity' ; import chokidar from 'chokidar' ; import { app } from 'electron' ; import debounce from 'lodash/debounce' ; import YAML from 'yaml' ; import { downloadFile } from './net' ; class Directory { declare path : string ; constructor ( dir ) { this . path = dir ; } file ( basename ) { return path . resolve ( this . path , basename ) ; } async ensure ( basename ) { const file = this . file ( basename ) ; try { await fs . promises . mkdir ( path . dirname ( file ) ) ; } catch { } } async read ( basename ) { try { const content = await fs . promises . readFile ( this . file ( basename ) ) ; return content . toString ( ) ; } catch { return null ; } } async write ( basename , content ) { await this . ensure ( basename ) ; const file = this . file ( basename ) ; return fs . promises . writeFile ( file , content + '\n' ) ; } watch ( basename , updater ) { const watcher = chokidar . watch ( this . file ( basename ) ) ; try { return watcher . on ( 'all' , debounce ( updater , 500 ) ) ; } catch { return null ; } } require < T > ( basename ) { const file = this . file ( basename ) ; try { return require ( file ) as T ; } catch { return null ; } } async download ( basename , url , force ? ) { if ( ! force ) { const data = await this . read ( basename ) ; if ( data ) return data ; } await this . ensure ( basename ) ; const file = this . file ( basename ) ; await downloadFile ( url , file ) ; return this . read ( basename ) ; } async loadYAML < T > ( basename ) { try { const content = await this . read ( basename ) ; if ( ! content ) return null ; return YAML . parse ( content ) as T ; } catch { return null ; } } async updateYAML ( basename , data ) { const content = await this . read ( basename ) ; if ( ! content ) { const created = YAML . stringify ( data ) ; return this . write ( basename , '---\n' + created . trim ( ) + '\n' ) ; } else { const updated = updateYamlDocument ( data , content , { keepArrayIndent : true } ) ; return this . write ( basename , updated . trim ( ) + '\n' ) ; } } useYAML < T > ( basename , defaultValue , afterTriggered ? ) { return customRef < T > ( ( track , trigger ) => { let data = defaultValue ; const reactiveEffect = effect ( async ( ) => { const result = await this . loadYAML < T > ( basename ) ; if ( result ) { data = result ; } else { data = defaultValue ; } trigger ( ) ; if ( afterTriggered ) { afterTriggered ( ) ; } } ) ; this . watch ( basename , ( ) => { reactiveEffect ( ) ; } ) ; return { get : ( ) => { track ( ) ; return data ; } , set : value => { this . updateYAML ( basename , value ) ; } , } ; } ) ; } } const rootDir = path . join ( __dirname , '../../' ) ; const userDataDir = app . isPackaged ? app . getPath ( 'userData' ) : path . join ( rootDir , 'userdata/' ) ; const resourcesDir = path . join ( rootDir , 'resources/' ) ; const userData = new Directory ( userDataDir ) ; const resources = new Directory ( resourcesDir ) ; export { Directory , rootDir , userData , resources , } ;