import * as path from 'path' ; import * as fs from 'fs-extra' ; import { RegistryEntry } from './RegistryEntry' ; import { IRegistry } from '../interfaces/IRegistry' ; import { FileSystemUtil } from '../util/FileSystemUtil' ; import { EventEmitter } from 'events' ; export abstract class FileRegistry < T extends RegistryEntry > extends EventEmitter implements IRegistry < RegistryEntry > { public static EVENT_NAME : string = 'registryUpdated' ; protected readonly FILE_NAME : string = '.config.json' ; private registryPath : string ; protected constructor ( private registryName ) { super ( ) ; } public setRegistryPath ( registryPath ) { this . registryPath = registryPath ; } public getRegistryPath ( ) { return this . registryPath ; } public async getAll ( ) { return await this . getEntries ( ) ; } public async get ( name ) { const entries = await this . getEntries ( ) ; const entry = entries . find ( ( item ) => item . name === name ) ; if ( ! entry ) { throw new Error ( `Entry "${ name }" in registry "${ this . registryName }" does not exist` ) ; } return entry ; } public async exists ( name ) { const entries = await this . getEntries ( ) ; return entries . some ( ( item ) => item . name === name ) ; } public async add ( entry ) { const name = entry . name ; const exists = await this . exists ( name ) ; if ( exists ) { throw new Error ( `Entry "${ name }" in registry "${ this . registryName }" already exists` ) ; } await this . updateEntries ( entry ) ; } public async update ( newEntry ) { const name = newEntry . name ; const exists = await this . exists ( name ) ; if ( ! exists ) { throw new Error ( `Entry "${ name }" in registry "${ this . registryName }" does not exist` ) ; } await this . updateEntries ( newEntry ) ; } public async delete ( name , ignoreNotExists = false ) { const exists = await this . exists ( name ) ; if ( ! exists && ! ignoreNotExists ) { throw new Error ( `Entry "${ name }" in registry "${ this . registryName }" does not exist` ) ; } else if ( ! exists && ignoreNotExists ) { return ; } const homeExtDir = FileSystemUtil . getDirPath ( this . registryPath ) ; const entryPath = path . join ( homeExtDir , this . registryName , name ) ; await fs . remove ( entryPath ) ; this . emit ( FileRegistry . EVENT_NAME , this . registryName ) ; } public async clear ( ) { const homeExtDir = FileSystemUtil . getDirPath ( this . registryPath ) ; const registryPath = path . join ( homeExtDir , this . registryName ) ; await fs . emptyDir ( registryPath ) ; this . emit ( FileRegistry . EVENT_NAME , this . registryName ) ; } protected async getEntries ( ) { const homeExtDir = FileSystemUtil . getDirPath ( this . registryPath ) ; const registryPath = path . join ( homeExtDir , this . registryName ) ; await fs . ensureDir ( registryPath ) ; const registryEntryNames = await fs . readdir ( registryPath ) ; const entries = [ ] ; for ( const entryName of registryEntryNames ) { const entryPath = path . join ( registryPath , entryName , this . FILE_NAME ) ; const exists = await fs . pathExists ( entryPath ) ; if ( exists ) { const entry = await fs . readJSON ( entryPath ) ; entries . push ( entry ) ; } } return entries ; } private async updateEntries ( entry ) { const homeExtDir = FileSystemUtil . getDirPath ( this . registryPath ) ; const registryPath = path . join ( homeExtDir , this . registryName ) ; const entryDir = path . join ( registryPath , entry . name ) ; await fs . ensureDir ( entryDir ) ; const entryPath = path . join ( entryDir , this . FILE_NAME ) ; await fs . writeJSON ( entryPath , entry ) ; this . emit ( FileRegistry . EVENT_NAME , this . registryName ) ; } }