import * as Path from 'path' ; import * as Fs from 'fs' ; import isUncPath from 'is-unc-path' ; import { RepositoryOptions } from '@lib/frameworks/repository' ; import { FrameworkOptions } from '@lib/frameworks/framework' ; import { getFrameworkByType } from '@lib/frameworks' ; /**
 * The required format for validation errors.
 */ export type ValidationErrors = { [ index ] : Array < string > ; } ; /**
 * Potential repository options (i.e. not necessarily valid).
 */ export type PotentialRepositoryOptions = RepositoryOptions & { path ? : string ; } ; /**
 * Potential framework options (i.e. not necessarily valid).
 */ export type PotentialFrameworkOptions = FrameworkOptions & { name ? : string ; type ? : string ; command ? : string ; path ? : string ; sshHost ? : string ; sshUser ? : string | null ; sshPort ? : number | null ; sshIdentity ? : string | null ; } ; /**
 * A generic validation class.
 */ export class Validator { protected errors : ValidationErrors = { } ; param data public validate ( data ) { this . reset ( ) ; } param path public isDirectory ( path ) { try { return Fs . statSync ( path ) . isDirectory ( ) ; } catch ( error ) { if ( error . code === 'ENOENT' ) { return false ; } throw error ; } } param path public isFile ( path ) { try { return Fs . statSync ( path ) . isFile ( ) ; } catch ( error ) { if ( error . code === 'ENOENT' ) { return false ; } throw error ; } } /**
     * Whether the current instance is valid.
     */ public isValid ( ) { return this . hasErrors ( ) ; } /**
     * Reset errors in the current instance.
     */ public reset ( fields ? ) { Object . keys ( this . errors ) . forEach ( key => { if ( ! fields || fields . includes ( key ) ) { this . errors [ key ] = [ ] ; } } ) ; } param key public hasErrors ( key ? ) { if ( typeof key === 'undefined' ) { let hasErrors = true ; Object . keys ( this . errors ) . forEach ( key => { if ( this . errors [ key ] . length > 0 ) { hasErrors = false ; } } ) ; return hasErrors ; } return this . errors [ key ] && this . errors [ key ] . length > 0 ; } param key public getErrors ( key ? ) { if ( ! key ) { return this . errors ; } if ( ! this . hasErrors ( key ) ) { return null ; } return this . errors [ key ] ; } param path param path public addError ( key , message ) { if ( typeof this . errors [ key ] === 'undefined' ) { this . errors [ key ] = [ ] ; } this . errors [ key ] . push ( message ) ; } } /**
 * A validation class for repository objects.
 */ export class RepositoryValidator extends Validator { protected existing : Array < string > ; constructor ( existing ) { super ( ) ; this . existing = existing ; this . errors = { path : [ ] } ; } param options public validate ( options ) { super . validate ( options ) ; if ( ! options . path ) { this . addError ( 'path' , 'Please enter a repository path.' ) ; } else if ( __WIN32__ && isUncPath ( options . path ) ) { this . addError ( 'path' , 'UNC paths are not supported.' ) ; } else if ( ! this . isDirectory ( options . path ) ) { this . addError ( 'path' , 'Please enter a valid repository directory.' ) ; } else if ( this . existing . includes ( options . path ) ) { this . addError ( 'path' , 'The project already contains this repository.' ) ; } return this ; } } /**
 * A validation class for framework objects.
 */ export class FrameworkValidator extends Validator { public readonly repositoryPath : string ; constructor ( repositoryPath ) { super ( ) ; this . errors = { name : [ ] , type : [ ] , command : [ ] , path : [ ] , sshHost : [ ] , sshUser : [ ] , sshPort : [ ] , sshIdentity : [ ] } ; this . repositoryPath = repositoryPath ; } param options public validate ( options ) { super . validate ( options ) ; if ( ! options . name ) { this . addError ( 'name' , 'Please enter a framework name.' ) ; } if ( ! options . type ) { this . addError ( 'type' , 'Please select a framework type.' ) ; } else if ( ! getFrameworkByType ( options . type ) ) { this . addError ( 'type' , 'Framework type "' + options . type + '" is invalid.' ) ; } if ( ! options . command ) { this . addError ( 'command' , 'Please enter a framework command.' ) ; } if ( options . path ) { if ( Path . isAbsolute ( options . path ) ) { this . addError ( 'path' , 'Please enter a path relative to the repository directory.' ) ; } else if ( ! this . isDirectory ( Path . join ( this . repositoryPath , options . path ) ) ) { this . addError ( 'path' , 'Please enter a valid directory relative to the repository directory.' ) ; } } if ( options . sshPort ) { if ( ! String ( options . sshPort ) . match ( /^([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$/ ) ) { this . addError ( 'sshPort' , 'Please enter a valid port number.' ) ; } } const framework = getFrameworkByType ( options . type ) ; if ( framework ) { framework . validate ( this , options ) ; } return this ; } }