UNPKG

ntts

Version:

A CLI tool for refactoring an existing NodeJs application to a fully functional TypeScript application.

94 lines (85 loc) 4.05 kB
import { ImportDeclaration, ImportSpecifier, SourceFile, VariableDeclarationKind, } from 'ts-morph'; import ImportCreator from '../../helpers/import-creator/import-creator'; import VariableNameGenerator from '../../helpers/variable-name-generator/variable-name-generator'; class ImportClauseRefactor { static refactorImportClause = ( importStatement: ImportDeclaration, usedImportNames: string[], sourceFile: SourceFile, ): string[] => { const moduleSpecifier = importStatement.getModuleSpecifierValue(); const importedSourceFile = importStatement.isModuleSpecifierRelative() && importStatement.getModuleSpecifierSourceFile(); if (importedSourceFile) { this.refactorDefaultImport(importStatement, moduleSpecifier, importedSourceFile, sourceFile); return this.refactorNamedImports(importStatement, usedImportNames, importedSourceFile, sourceFile); } return usedImportNames; }; private static refactorDefaultImport = ( importStatement: ImportDeclaration, moduleSpecifier: string, importedSourceFile: SourceFile, sourceFile: SourceFile, ) => { const defaultImport = importStatement.getDefaultImport()?.getText(); if (defaultImport && !this.hasDefaultExport(importedSourceFile)) { if (importStatement.getNamedImports().length > 0) { ImportCreator.addNamespaceImport(defaultImport, moduleSpecifier, sourceFile); importStatement.removeDefaultImport(); } else { importStatement.removeDefaultImport().setNamespaceImport(defaultImport); } } }; private static refactorNamedImports = ( importStatement: ImportDeclaration, usedImportNames: string[], importedSourceFile: SourceFile, sourceFile: SourceFile, ): string[] => { const namedImports = importStatement.getNamedImports(); if (namedImports.length > 0) { const exportedList = this.getExportedList(importedSourceFile); const defaultImports = namedImports.filter((namedImport) => !exportedList.includes(namedImport.getName())); const defaultImportName = importStatement.getDefaultImport()?.getText(); if (defaultImportName && defaultImports.length > 0) { this.createObjectDestructuring(importStatement, defaultImports, defaultImportName, sourceFile); defaultImports.forEach((d) => d.remove()); } if (!defaultImportName && defaultImports.length > 0) { const importName = VariableNameGenerator.variableNameFromImportId(importStatement.getModuleSpecifierValue()); const initializer = VariableNameGenerator.getUsableVariableName(importName, usedImportNames); importStatement.setDefaultImport(initializer); this.createObjectDestructuring(importStatement, defaultImports, initializer, sourceFile); defaultImports.forEach((d) => d.remove()); return usedImportNames.concat(importName); } } return usedImportNames; }; private static getExportedList = (importedSourceFile: SourceFile): string[] => importedSourceFile .getExportDeclarations() .reduce((exportedNames: string[], exportDeclaration) => { const names = exportDeclaration .getNamedExports() .map((named) => named.getAliasNode()?.getText() || named.getName()); return exportedNames.concat(...names); }, []); private static createObjectDestructuring = ( importStatement: ImportDeclaration, defaultImports: ImportSpecifier[], initializer: string, sourceFile: SourceFile, ) => { const index = importStatement.getChildIndex(); const objectDestructuring = defaultImports.map((i) => (i.getAliasNode() ? `${i.getName()}: ${i.getAliasNode()}` : i.getName())).join(', '); sourceFile.insertVariableStatement(index + 1, { declarationKind: VariableDeclarationKind.Const, declarations: [{ name: `{ ${objectDestructuring} }`, initializer }], }); }; private static hasDefaultExport = (sourceFile: SourceFile): boolean => !!sourceFile.getDefaultExportSymbol(); } export default ImportClauseRefactor;