import * as _ from 'lodash' ; import { MiscellaneousData } from '../interfaces/miscellaneous-data.interface' ; import { ParsedData } from '../interfaces/parsed-data.interface' ; import { RouteInterface } from '../interfaces/routes.interface' ; import AngularApiUtil from '../../utils/angular-api.util' ; import { IApiSourceResult } from '../../utils/api-source-result.interface' ; import { getNamesCompareFn } from '../../utils/utils' ; import { IEnumDecDep , IFunctionDecDep , IGuardDep , IInjectableDep , IInterceptorDep , IInterfaceDep , IPipeDep , ITypeAliasDecDep } from '../compiler/angular/dependencies.interfaces' ; import { IComponentDep } from '../compiler/angular/deps/component-dep.factory' ; import { IControllerDep } from '../compiler/angular/deps/controller-dep.factory' ; import { IDirectiveDep } from '../compiler/angular/deps/directive-dep.factory' ; import { IModuleDep } from '../compiler/angular/deps/module-dep.factory' ; const traverse = require ( 'traverse' ) ; export class DependenciesEngine { public rawData : ParsedData ; public modules : Object [ ] ; public rawModules : Object [ ] ; public rawModulesForOverview : Object [ ] ; public components : Object [ ] ; public controllers : Object [ ] ; public entities : Object [ ] ; public directives : Object [ ] ; public injectables : Object [ ] ; public interceptors : Object [ ] ; public guards : Object [ ] ; public interfaces : Object [ ] ; public routes : RouteInterface ; public pipes : Object [ ] ; public classes : Object [ ] ; public miscellaneous : MiscellaneousData = { variables : [ ] , functions : [ ] , typealiases : [ ] , enumerations : [ ] , groupedVariables : [ ] , groupedFunctions : [ ] , groupedEnumerations : [ ] , groupedTypeAliases : [ ] } ; private static instance : DependenciesEngine ; private constructor ( ) { } public static getInstance ( ) { if ( ! DependenciesEngine . instance ) { DependenciesEngine . instance = new DependenciesEngine ( ) ; } return DependenciesEngine . instance ; } private updateModulesDeclarationsExportsTypes ( ) { let mergeTypes = entry => { let directive = this . findInCompodocDependencies ( entry . name , this . directives , entry . file ) ; if ( typeof directive . data !== 'undefined' ) { entry . type = 'directive' ; entry . id = directive . data . id ; } let component = this . findInCompodocDependencies ( entry . name , this . components , entry . file ) ; if ( typeof component . data !== 'undefined' ) { entry . type = 'component' ; entry . id = component . data . id ; } let pipe = this . findInCompodocDependencies ( entry . name , this . pipes , entry . file ) ; if ( typeof pipe . data !== 'undefined' ) { entry . type = 'pipe' ; entry . id = pipe . data . id ; } } ; this . modules . forEach ( module => { module . declarations . forEach ( declaration => { mergeTypes ( declaration ) ; } ) ; module . exports . forEach ( expt => { mergeTypes ( expt ) ; } ) ; module . entryComponents . forEach ( ent => { mergeTypes ( ent ) ; } ) ; } ) ; } public init ( data ) { traverse ( data ) . forEach ( function ( node ) { if ( node ) { if ( node . parent ) { delete node . parent ; } if ( node . initializer ) { delete node . initializer ; } } } ) ; this . rawData = data ; this . modules = _ . sortBy ( this . rawData . modules , [ el => el . name . toLowerCase ( ) ] ) ; this . rawModulesForOverview = _ . sortBy ( data . modulesForGraph , [ el => el . name . toLowerCase ( ) ] ) ; this . rawModules = _ . sortBy ( data . modulesForGraph , [ el => el . name . toLowerCase ( ) ] ) ; this . components = _ . sortBy ( this . rawData . components , [ el => el . name . toLowerCase ( ) ] ) ; this . controllers = _ . sortBy ( this . rawData . controllers , [ el => el . name . toLowerCase ( ) ] ) ; this . entities = _ . sortBy ( this . rawData . entities , [ el => el . name . toLowerCase ( ) ] ) ; this . directives = _ . sortBy ( this . rawData . directives , [ el => el . name . toLowerCase ( ) ] ) ; this . injectables = _ . sortBy ( this . rawData . injectables , [ el => el . name . toLowerCase ( ) ] ) ; this . interceptors = _ . sortBy ( this . rawData . interceptors , [ el => el . name . toLowerCase ( ) ] ) ; this . guards = _ . sortBy ( this . rawData . guards , [ el => el . name . toLowerCase ( ) ] ) ; this . interfaces = _ . sortBy ( this . rawData . interfaces , [ el => el . name . toLowerCase ( ) ] ) ; this . pipes = _ . sortBy ( this . rawData . pipes , [ el => el . name . toLowerCase ( ) ] ) ; this . classes = _ . sortBy ( this . rawData . classes , [ el => el . name . toLowerCase ( ) ] ) ; this . miscellaneous = this . rawData . miscellaneous ; this . prepareMiscellaneous ( ) ; this . updateModulesDeclarationsExportsTypes ( ) ; this . routes = this . rawData . routesTree ; this . manageDuplicatesName ( ) ; this . cleanRawModulesNames ( ) ; } private cleanRawModulesNames ( ) { this . rawModulesForOverview = this . rawModulesForOverview . map ( module => { module . name = module . name . replace ( '$' , '' ) ; return module ; } ) ; } private findInCompodocDependencies ( name , data , file ? ) { let _result = { source : 'internal' , data : undefined } ; let nameFoundCounter = 0 ; if ( data && data . length > 0 ) { for ( let i = 0 ; i < data . length ; i ++ ) { if ( typeof name !== 'undefined' ) { if ( typeof file !== 'undefined' ) { if ( name . indexOf ( data [ i ] . name ) !== - 1 && file . replace ( /\\/g , '/' ) . indexOf ( data [ i ] . file ) !== - 1 ) { nameFoundCounter += 1 ; _result . data = data [ i ] ; } } else { if ( name . indexOf ( data [ i ] . name ) !== - 1 ) { nameFoundCounter += 1 ; _result . data = data [ i ] ; } } } } if ( nameFoundCounter > 1 ) { let found = false ; for ( let i = 0 ; i < data . length ; i ++ ) { if ( typeof name !== 'undefined' ) { if ( typeof file !== 'undefined' ) { if ( name === data [ i ] . name && file . replace ( /\\/g , '/' ) . indexOf ( data [ i ] . file ) !== - 1 ) { found = true ; _result . data = data [ i ] ; } } else { if ( name === data [ i ] . name ) { found = true ; _result . data = data [ i ] ; } } } } if ( ! found ) { _result = { source : 'internal' , data : undefined } ; } } } return _result ; } private manageDuplicatesName ( ) { let processDuplicates = ( element , index , array ) => { let elementsWithSameName = _ . filter ( array , { name : element . name } ) ; if ( elementsWithSameName . length > 1 ) { for ( let i = 1 ; i < elementsWithSameName . length ; i ++ ) { let elementToEdit = elementsWithSameName [ i ] ; if ( typeof elementToEdit . isDuplicate === 'undefined' ) { elementToEdit . isDuplicate = true ; elementToEdit . duplicateId = i ; elementToEdit . duplicateName = elementToEdit . name + '-' + elementToEdit . duplicateId ; elementToEdit . id = elementToEdit . id + '-' + elementToEdit . duplicateId ; } } } return element ; } ; this . classes = this . classes . map ( processDuplicates ) ; this . interfaces = this . interfaces . map ( processDuplicates ) ; this . injectables = this . injectables . map ( processDuplicates ) ; this . pipes = this . pipes . map ( processDuplicates ) ; this . interceptors = this . interceptors . map ( processDuplicates ) ; this . guards = this . guards . map ( processDuplicates ) ; this . modules = this . modules . map ( processDuplicates ) ; this . components = this . components . map ( processDuplicates ) ; this . controllers = this . controllers . map ( processDuplicates ) ; this . entities = this . entities . map ( processDuplicates ) ; this . directives = this . directives . map ( processDuplicates ) ; } public find ( name ) { const searchFunctions = [ ( ) => this . findInCompodocDependencies ( name , this . injectables ) , ( ) => this . findInCompodocDependencies ( name , this . interceptors ) , ( ) => this . findInCompodocDependencies ( name , this . guards ) , ( ) => this . findInCompodocDependencies ( name , this . interfaces ) , ( ) => this . findInCompodocDependencies ( name , this . classes ) , ( ) => this . findInCompodocDependencies ( name , this . components ) , ( ) => this . findInCompodocDependencies ( name , this . controllers ) , ( ) => this . findInCompodocDependencies ( name , this . entities ) , ( ) => this . findInCompodocDependencies ( name , this . directives ) , ( ) => this . findInCompodocDependencies ( name , this . miscellaneous . variables ) , ( ) => this . findInCompodocDependencies ( name , this . miscellaneous . functions ) , ( ) => this . findInCompodocDependencies ( name , this . miscellaneous . typealiases ) , ( ) => this . findInCompodocDependencies ( name , this . miscellaneous . enumerations ) , ( ) => AngularApiUtil . findApi ( name ) ] ; for ( let searchFunction of searchFunctions ) { let result = searchFunction ( ) ; if ( result . data ) { return result ; } } return undefined ; } public update ( updatedData ) { if ( updatedData . modules . length > 0 ) { _ . forEach ( updatedData . modules , ( module ) => { const _index = _ . findIndex ( this . modules , { name : module . name } ) ; this . modules [ _index ] = module ; } ) ; } if ( updatedData . components . length > 0 ) { _ . forEach ( updatedData . components , ( component ) => { const _index = _ . findIndex ( this . components , { name : component . name } ) ; this . components [ _index ] = component ; } ) ; } if ( updatedData . controllers . length > 0 ) { _ . forEach ( updatedData . controllers , ( controller ) => { const _index = _ . findIndex ( this . controllers , { name : controller . name } ) ; this . controllers [ _index ] = controller ; } ) ; } if ( updatedData . entities . length > 0 ) { _ . forEach ( updatedData . entities , ( entity ) => { const _index = _ . findIndex ( this . entities , { name : entity . name } ) ; this . entities [ _index ] = entity ; } ) ; } if ( updatedData . directives . length > 0 ) { _ . forEach ( updatedData . directives , ( directive ) => { const _index = _ . findIndex ( this . directives , { name : directive . name } ) ; this . directives [ _index ] = directive ; } ) ; } if ( updatedData . injectables . length > 0 ) { _ . forEach ( updatedData . injectables , ( injectable ) => { const _index = _ . findIndex ( this . injectables , { name : injectable . name } ) ; this . injectables [ _index ] = injectable ; } ) ; } if ( updatedData . interceptors . length > 0 ) { _ . forEach ( updatedData . interceptors , ( interceptor ) => { const _index = _ . findIndex ( this . interceptors , { name : interceptor . name } ) ; this . interceptors [ _index ] = interceptor ; } ) ; } if ( updatedData . guards . length > 0 ) { _ . forEach ( updatedData . guards , ( guard ) => { const _index = _ . findIndex ( this . guards , { name : guard . name } ) ; this . guards [ _index ] = guard ; } ) ; } if ( updatedData . interfaces . length > 0 ) { _ . forEach ( updatedData . interfaces , ( int ) => { const _index = _ . findIndex ( this . interfaces , { name : int . name } ) ; this . interfaces [ _index ] = int ; } ) ; } if ( updatedData . pipes . length > 0 ) { _ . forEach ( updatedData . pipes , ( pipe ) => { const _index = _ . findIndex ( this . pipes , { name : pipe . name } ) ; this . pipes [ _index ] = pipe ; } ) ; } if ( updatedData . classes . length > 0 ) { _ . forEach ( updatedData . classes , ( classe ) => { const _index = _ . findIndex ( this . classes , { name : classe . name } ) ; this . classes [ _index ] = classe ; } ) ; } /**
         * Miscellaneous update
         */ if ( updatedData . miscellaneous . variables . length > 0 ) { _ . forEach ( updatedData . miscellaneous . variables , ( variable ) => { const _index = _ . findIndex ( this . miscellaneous . variables , { name : variable . name , file : variable . file } ) ; this . miscellaneous . variables [ _index ] = variable ; } ) ; } if ( updatedData . miscellaneous . functions . length > 0 ) { _ . forEach ( updatedData . miscellaneous . functions , ( func ) => { const _index = _ . findIndex ( this . miscellaneous . functions , { name : func . name , file : func . file } ) ; this . miscellaneous . functions [ _index ] = func ; } ) ; } if ( updatedData . miscellaneous . typealiases . length > 0 ) { _ . forEach ( updatedData . miscellaneous . typealiases , ( typealias ) => { const _index = _ . findIndex ( this . miscellaneous . typealiases , { name : typealias . name , file : typealias . file } ) ; this . miscellaneous . typealiases [ _index ] = typealias ; } ) ; } if ( updatedData . miscellaneous . enumerations . length > 0 ) { _ . forEach ( updatedData . miscellaneous . enumerations , ( enumeration ) => { const _index = _ . findIndex ( this . miscellaneous . enumerations , { name : enumeration . name , file : enumeration . file } ) ; this . miscellaneous . enumerations [ _index ] = enumeration ; } ) ; } this . prepareMiscellaneous ( ) ; } public findInCompodoc ( name ) { let mergedData = _ . concat ( [ ] , this . modules , this . components , this . controllers , this . entities , this . directives , this . injectables , this . interceptors , this . guards , this . interfaces , this . pipes , this . classes , this . miscellaneous . enumerations , this . miscellaneous . typealiases , this . miscellaneous . variables , this . miscellaneous . functions ) ; let result = _ . find ( mergedData , { name : name } as any ) ; return result || false ; } private prepareMiscellaneous ( ) { this . miscellaneous . variables . sort ( getNamesCompareFn ( ) ) ; this . miscellaneous . functions . sort ( getNamesCompareFn ( ) ) ; this . miscellaneous . enumerations . sort ( getNamesCompareFn ( ) ) ; this . miscellaneous . typealiases . sort ( getNamesCompareFn ( ) ) ; this . miscellaneous . groupedVariables = _ . groupBy ( this . miscellaneous . variables , 'file' ) ; this . miscellaneous . groupedFunctions = _ . groupBy ( this . miscellaneous . functions , 'file' ) ; this . miscellaneous . groupedEnumerations = _ . groupBy ( this . miscellaneous . enumerations , 'file' ) ; this . miscellaneous . groupedTypeAliases = _ . groupBy ( this . miscellaneous . typealiases , 'file' ) ; } public getModule ( name ) { return _ . find ( this . modules , [ 'name' , name ] ) ; } public getRawModule ( name ) { return _ . find ( this . rawModules , [ 'name' , name ] ) ; } public getModules ( ) { return this . modules ; } public getComponents ( ) { return this . components ; } public getControllers ( ) { return this . controllers ; } public getEntities ( ) { return this . entities ; } public getDirectives ( ) { return this . directives ; } public getInjectables ( ) { return this . injectables ; } public getInterceptors ( ) { return this . interceptors ; } public getGuards ( ) { return this . guards ; } public getInterfaces ( ) { return this . interfaces ; } public getRoutes ( ) { return this . routes ; } public getPipes ( ) { return this . pipes ; } public getClasses ( ) { return this . classes ; } public getMiscellaneous ( ) { return this . miscellaneous ; } } export default DependenciesEngine . getInstance ( ) ;