import { Metadata } from './metadata' ; import { Folder } from '../folder' ; import { File } from '../file' ; import { Container , autoinject , Instance } from '../libs/container' ; @ autoinject export class Structure { plainFileNames : string [ ] ; entryPoint : Folder ; flatFileStructure : File [ ] ; constructor ( private container , private metadata ) { this . plainFileNames = this . metadata . getAll ( ) . map ( m => m . fileName ) ; const prefix = this . getPrefixPath ( this . plainFileNames ) ; const fileNamesWithoutPrefix = this . removePathPrefix ( this . plainFileNames , prefix ) ; const { treeStructure , flatFileStructure } = this . createFolderStructure ( fileNamesWithoutPrefix ) ; const optimized = this . reduceSingleChildFolders ( treeStructure ) ; this . entryPoint = optimized ; this . entryPoint . updateState ( { name : prefix , isRoot : true } ) ; this . flatFileStructure = flatFileStructure ; } param { string [ ] } fileNames return { string } private getPrefixPath ( fileNames ) { if ( ! Array . isArray ( fileNames ) ) { throw new Error ( `Expected array, ${ typeof fileNames } given!` ) ; } if ( fileNames . length === 0 ) { return '' ; } let sourcePathParts = fileNames [ 0 ] . split ( '/' ) ; if ( fileNames . length === 1 ) { sourcePathParts . pop ( ) ; return sourcePathParts . join ( '/' ) ; } for ( let i = 1 ; i < fileNames . length ; i ++ ) { let filePathParts = fileNames [ i ] . split ( '/' ) ; for ( let ii = 0 ; ii < sourcePathParts . length ; ii ++ ) { if ( sourcePathParts [ ii ] !== filePathParts [ ii ] ) { sourcePathParts = sourcePathParts . slice ( 0 , ii ) ; break ; } } } return sourcePathParts . join ( '/' ) ; } param { string [ ] } fileNames param { string } prefix return { string [ ] } private removePathPrefix ( fileNames , prefix ) { if ( prefix . length === 0 ) { return fileNames . slice ( 0 ) ; } let output = [ ] ; for ( let fileName of fileNames ) { output . push ( fileName . substring ( ( prefix + '/' ) . length ) ) ; } return output ; } param { string } fileNames return { any } private createFolderStructure ( fileNames ) { const mainFolder = this . container . get ( Instance . of ( Folder ) ) . init ( '' ) ; const flatFileStructure = [ ] ; if ( ! Array . isArray ( fileNames ) || fileNames . length === 0 ) { throw new Error ( `Expected array, ${ typeof fileNames } given!` ) ; } for ( let i = 0 ; i < fileNames . length ; i ++ ) { const fileName = fileNames [ i ] ; const fileNameParts = fileName . split ( '/' ) ; let currentFolder = mainFolder ; for ( let ii = 0 ; ii < fileNameParts . length ; ii ++ ) { const part = fileNameParts [ ii ] ; if ( ii === fileNameParts . length - 1 ) { const file = this . container . get ( Instance . of ( File ) ) . init ( part , i ) ; currentFolder . addFile ( file ) ; flatFileStructure . push ( file ) ; } else { if ( ! currentFolder . hasFolder ( part ) ) { const newSubFolder = this . container . get ( Instance . of ( Folder ) ) . init ( part ) ; currentFolder . addFolder ( newSubFolder ) ; currentFolder = newSubFolder ; } else { currentFolder = currentFolder . getFolder ( part ) ; } } } } return { treeStructure : mainFolder , flatFileStructure } ; } private reduceSingleChildFolders ( folder ) { if ( folder . subfoldersSize === 0 ) { return folder ; } else if ( folder . subfoldersSize === 1 && folder . filesSize === 0 ) { const childFolder = folder . getFolders ( ) [ 0 ] ; folder . updateState ( { name : `${ folder . state . name }/${ childFolder . state . name }` } ) ; folder . dropFolders ( ) ; folder . addFolder ( ... childFolder . getFolders ( ) ) ; folder . addFile ( ... childFolder . getFiles ( ) ) ; this . reduceSingleChildFolders ( folder ) ; } else { for ( const subFolder of folder . getFolders ( ) ) { this . reduceSingleChildFolders ( subFolder ) ; } } return folder ; } }