import * as path from 'path' ; import { Project , ts , PropertyDeclaration , SyntaxKind , VariableDeclaration } from 'ts-morph' ; import FileEngine from '../app/engines/file.engine' ; const ast = new Project ( ) ; export class ImportsUtil { private static instance : ImportsUtil ; private constructor ( ) { } public static getInstance ( ) { if ( ! ImportsUtil . instance ) { ImportsUtil . instance = new ImportsUtil ( ) ; } return ImportsUtil . instance ; } param srcFile param variableName param variableValue private findInEnums ( srcFile , variableName , variableValue ) { let res = '' ; srcFile . getEnum ( e => { if ( e . getName ( ) === variableName ) { e . getMember ( m => { if ( m . getName ( ) === variableValue ) { res = m . getValue ( ) ; } } ) ; } } ) ; return res ; } param srcFile param variableName param variableValue private findInClasses ( srcFile , variableName , variableValue ) { let res = '' ; srcFile . getClass ( c => { let staticProperty = c . getStaticProperty ( variableValue ) ; if ( staticProperty ) { if ( staticProperty . getInitializer ( ) ) { res = staticProperty . getInitializer ( ) . getText ( ) ; } } } ) ; return res ; } param variableDeclaration param variablesAttributes private findInObjectVariableDeclaration ( variableDeclaration , variablesAttributes ) { let variableKind = variableDeclaration . getKind ( ) ; if ( variableKind && variableKind === SyntaxKind . VariableDeclaration ) { let initializer = variableDeclaration . getInitializer ( ) ; if ( initializer ) { let initializerKind = initializer . getKind ( ) ; if ( initializerKind && initializerKind === SyntaxKind . ObjectLiteralExpression ) { let compilerNode = initializer . compilerNode as ts . ObjectLiteralExpression , finalValue = '' ; let depth = 0 ; let loopProperties = properties => { properties . forEach ( prop => { if ( prop . name ) { if ( variablesAttributes [ depth + 1 ] ) { if ( prop . name . getText ( ) === variablesAttributes [ depth + 1 ] ) { if ( prop . initializer ) { if ( prop . initializer . properties ) { depth += 1 ; loopProperties ( prop . initializer . properties ) ; } else { finalValue = prop . initializer . text ; } } else { finalValue = prop . initializer . text ; } } } } } ) ; } ; loopProperties ( compilerNode . properties ) ; return finalValue ; } } } } param { string } inputVariableName return { [ type ] } public findValueInImportOrLocalVariables ( inputVariableName , sourceFile , decoratorType ? ) { let metadataVariableName = inputVariableName , searchedImport , aliasOriginalName = '' , foundWithNamedImport = false , foundWithDefaultImport = false , foundWithAlias = false ; const file = typeof ast . getSourceFile ( sourceFile . fileName ) !== 'undefined' ? ast . getSourceFile ( sourceFile . fileName ) : ast . addSourceFileAtPathIfExists ( sourceFile . fileName ) ; const imports = file . getImportDeclarations ( ) ; /**
         * Loop through all imports, and find one matching inputVariableName
         */ imports . forEach ( i => { let namedImports = i . getNamedImports ( ) , namedImportsLength = namedImports . length , j = 0 ; if ( namedImportsLength > 0 ) { for ( j ; j < namedImportsLength ; j ++ ) { let importName = namedImports [ j ] . getNameNode ( ) . getText ( ) as string , importAlias ; if ( namedImports [ j ] . getAliasNode ( ) ) { importAlias = namedImports [ j ] . getAliasNode ( ) . getText ( ) ; } if ( importName === metadataVariableName ) { foundWithNamedImport = true ; searchedImport = i ; break ; } if ( importAlias === metadataVariableName ) { foundWithNamedImport = true ; foundWithAlias = true ; aliasOriginalName = importName ; searchedImport = i ; break ; } } } const namespaceImport = i . getNamespaceImport ( ) ; if ( namespaceImport ) { const namespaceImportLocalName = namespaceImport . getText ( ) ; if ( namespaceImportLocalName === metadataVariableName ) { searchedImport = i ; } } if ( ! foundWithNamedImport ) { const defaultImport = i . getDefaultImport ( ) ; if ( defaultImport ) { const defaultImportText = defaultImport . getText ( ) ; if ( defaultImportText === metadataVariableName ) { foundWithDefaultImport = true ; searchedImport = i ; } } } } ) ; function hasFoundValues ( variableDeclaration ) { let variableKind = variableDeclaration . getKind ( ) ; if ( variableKind && variableKind === SyntaxKind . VariableDeclaration ) { let initializer = variableDeclaration . getInitializer ( ) ; if ( initializer ) { let initializerKind = initializer . getKind ( ) ; if ( initializerKind && initializerKind === SyntaxKind . ObjectLiteralExpression ) { let compilerNode = initializer . compilerNode as ts . ObjectLiteralExpression ; return compilerNode . properties ; } } } } if ( typeof searchedImport !== 'undefined' ) { let importPathReference = searchedImport . getModuleSpecifierSourceFile ( ) ; let importPath ; if ( typeof importPathReference !== 'undefined' ) { importPath = importPathReference . compilerNode . fileName ; const sourceFileImport = typeof ast . getSourceFile ( importPath ) !== 'undefined' ? ast . getSourceFile ( importPath ) : ast . addSourceFileAtPathIfExists ( importPath ) ; if ( sourceFileImport ) { let variableName = foundWithAlias ? aliasOriginalName : metadataVariableName ; let variableDeclaration = sourceFileImport . getVariableDeclaration ( variableName ) ; if ( variableDeclaration ) { return hasFoundValues ( variableDeclaration ) ; } else { const exportDeclarations = sourceFileImport . getExportedDeclarations ( ) ; if ( exportDeclarations && exportDeclarations . size > 0 ) { for ( const [ exportDeclarationKey , exportDeclarationValues ] of exportDeclarations ) { exportDeclarationValues . forEach ( exportDeclarationValue => { if ( exportDeclarationValue instanceof VariableDeclaration && exportDeclarationValue . getName ( ) === variableName ) { return hasFoundValues ( exportDeclarationValue ) ; } } ) ; } } } } } if ( ! importPathReference && decoratorType === 'template' && searchedImport . getModuleSpecifierValue ( ) . indexOf ( '.html' ) !== - 1 ) { const originalSourceFilePath = sourceFile . path ; const originalSourceFilePathFolder = originalSourceFilePath . substring ( 0 , originalSourceFilePath . lastIndexOf ( '/' ) ) ; const finalImportedPath = originalSourceFilePathFolder + '/' + searchedImport . getModuleSpecifierValue ( ) ; const finalImportedPathData = FileEngine . getSync ( finalImportedPath ) ; return finalImportedPathData ; } } else { const variableDeclaration = file . getVariableDeclaration ( metadataVariableName ) ; if ( variableDeclaration ) { let variableKind = variableDeclaration . getKind ( ) ; if ( variableKind && variableKind === SyntaxKind . VariableDeclaration ) { let initializer = variableDeclaration . getInitializer ( ) ; if ( initializer ) { let initializerKind = initializer . getKind ( ) ; if ( initializerKind && initializerKind === SyntaxKind . ObjectLiteralExpression ) { let compilerNode = initializer . compilerNode as ts . ObjectLiteralExpression ; return compilerNode . properties ; } else if ( initializerKind && ( initializerKind === SyntaxKind . StringLiteral || initializerKind === SyntaxKind . NoSubstitutionTemplateLiteral ) ) { if ( decoratorType === 'template' ) { return initializer . getText ( ) ; } else { return variableDeclaration . compilerNode ; } } else if ( initializerKind ) { return variableDeclaration . compilerNode ; } } } } } return [ ] ; } public getFileNameOfImport ( variableName , sourceFile ) { const file = typeof ast . getSourceFile ( sourceFile . fileName ) !== 'undefined' ? ast . getSourceFile ( sourceFile . fileName ) : ast . addSourceFileAtPath ( sourceFile . fileName ) ; const imports = file . getImportDeclarations ( ) ; let searchedImport , aliasOriginalName = '' , finalPath = '' , foundWithAlias = false ; imports . forEach ( i => { let namedImports = i . getNamedImports ( ) , namedImportsLength = namedImports . length , j = 0 ; if ( namedImportsLength > 0 ) { for ( j ; j < namedImportsLength ; j ++ ) { let importName = namedImports [ j ] . getNameNode ( ) . getText ( ) as string , importAlias ; if ( namedImports [ j ] . getAliasNode ( ) ) { importAlias = namedImports [ j ] . getAliasNode ( ) . getText ( ) ; } if ( importName === variableName ) { searchedImport = i ; break ; } if ( importAlias === variableName ) { foundWithAlias = true ; aliasOriginalName = importName ; searchedImport = i ; break ; } } } } ) ; if ( typeof searchedImport !== 'undefined' ) { let importPath = path . resolve ( path . dirname ( sourceFile . fileName ) + '/' + searchedImport . getModuleSpecifierValue ( ) + '.ts' ) ; let cleaner = ( process . cwd ( ) + path . sep ) . replace ( /\\/g , '/' ) ; finalPath = importPath . replace ( cleaner , '' ) ; } return finalPath ; } param { string } inputVariableName return { [ type ] } public findFilePathOfImportedVariable ( inputVariableName , sourceFilePath ) { let searchedImport , finalPath = '' , aliasOriginalName = '' , foundWithAlias = false ; const file = typeof ast . getSourceFile ( sourceFilePath ) !== 'undefined' ? ast . getSourceFile ( sourceFilePath ) : ast . addSourceFileAtPath ( sourceFilePath ) ; const imports = file . getImportDeclarations ( ) ; /**
         * Loop through all imports, and find one matching inputVariableName
         */ imports . forEach ( i => { let namedImports = i . getNamedImports ( ) , namedImportsLength = namedImports . length , j = 0 ; if ( namedImportsLength > 0 ) { for ( j ; j < namedImportsLength ; j ++ ) { let importName = namedImports [ j ] . getNameNode ( ) . getText ( ) as string , importAlias ; if ( namedImports [ j ] . getAliasNode ( ) ) { importAlias = namedImports [ j ] . getAliasNode ( ) . getText ( ) ; } if ( importName === inputVariableName ) { searchedImport = i ; break ; } if ( importAlias === inputVariableName ) { foundWithAlias = true ; aliasOriginalName = importName ; searchedImport = i ; break ; } } } } ) ; if ( typeof searchedImport !== 'undefined' ) { finalPath = path . resolve ( path . dirname ( sourceFilePath ) + '/' + searchedImport . getModuleSpecifierValue ( ) + '.ts' ) ; } return finalPath ; } param { string } inputVariableName return { [ type ] } public findPropertyValueInImportOrLocalVariables ( inputVariableName , sourceFile ) { let variablesAttributes = inputVariableName . split ( '.' ) , metadataVariableName = variablesAttributes [ 0 ] , searchedImport , aliasOriginalName = '' , foundWithAlias = false ; const file = typeof ast . getSourceFile ( sourceFile . fileName ) !== 'undefined' ? ast . getSourceFile ( sourceFile . fileName ) : ast . addSourceFileAtPath ( sourceFile . fileName ) ; const imports = file . getImportDeclarations ( ) ; /**
         * Loop through all imports, and find one matching inputVariableName
         */ imports . forEach ( i => { let namedImports = i . getNamedImports ( ) , namedImportsLength = namedImports . length , j = 0 ; if ( namedImportsLength > 0 ) { for ( j ; j < namedImportsLength ; j ++ ) { let importName = namedImports [ j ] . getNameNode ( ) . getText ( ) as string , importAlias ; if ( namedImports [ j ] . getAliasNode ( ) ) { importAlias = namedImports [ j ] . getAliasNode ( ) . getText ( ) ; } if ( importName === metadataVariableName ) { searchedImport = i ; break ; } if ( importAlias === metadataVariableName ) { foundWithAlias = true ; aliasOriginalName = importName ; searchedImport = i ; break ; } } } } ) ; let fileToSearchIn , variableDeclaration ; if ( typeof searchedImport !== 'undefined' ) { let importPath = path . resolve ( path . dirname ( sourceFile . fileName ) + '/' + searchedImport . getModuleSpecifierValue ( ) + '.ts' ) ; const sourceFileImport = typeof ast . getSourceFile ( importPath ) !== 'undefined' ? ast . getSourceFile ( importPath ) : ast . addSourceFileAtPath ( importPath ) ; if ( sourceFileImport ) { fileToSearchIn = sourceFileImport ; let variableName = foundWithAlias ? aliasOriginalName : metadataVariableName ; variableDeclaration = fileToSearchIn . getVariableDeclaration ( variableName ) ; } } else { fileToSearchIn = file ; variableDeclaration = fileToSearchIn . getVariableDeclaration ( metadataVariableName ) ; } if ( variableDeclaration ) { return this . findInObjectVariableDeclaration ( variableDeclaration , variablesAttributes ) ; } if ( variablesAttributes . length > 0 ) { if ( typeof fileToSearchIn !== 'undefined' ) { let val = this . findInEnums ( fileToSearchIn , metadataVariableName , variablesAttributes [ 1 ] ) ; if ( val !== '' ) { return val ; } val = this . findInClasses ( fileToSearchIn , metadataVariableName , variablesAttributes [ 1 ] ) ; if ( val !== '' ) { return val ; } } } } } export default ImportsUtil . getInstance ( ) ;