ts-import-types-cli
Version:
Autofix TypeScript types to be imported using `import type`
157 lines (156 loc) • 8.03 kB
JavaScript
;
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __spread = (this && this.__spread) || function () {
for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
return ar;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
exports.__esModule = true;
exports.tsImportTypes = void 0;
var chalk_1 = __importDefault(require("chalk"));
var os_1 = require("os");
var path_1 = require("path");
var ts_morph_1 = require("ts-morph");
var info = function () {
var messages = [];
for (var _i = 0; _i < arguments.length; _i++) {
messages[_i] = arguments[_i];
}
console.log(chalk_1["default"].blue.apply(chalk_1["default"], __spread(['i'], messages)));
};
var getRelativePath = function (sourceFile) {
return path_1.relative(process.cwd(), sourceFile.getFilePath());
};
var getSourceFiles = function (sourcePatterns, project) {
return sourcePatterns.length ? project.getSourceFiles(sourcePatterns) : project.getSourceFiles();
};
function tsImportTypes(_a) {
var dryRun = _a.dryRun, organiseImports = _a.organiseImports, sourcePatterns = _a.sourcePatterns, tsConfigFilePath = _a.tsConfigFilePath;
info('Analysing', path_1.relative(process.cwd(), tsConfigFilePath));
var project = new ts_morph_1.Project({ tsConfigFilePath: tsConfigFilePath });
var sourceFiles = getSourceFiles(sourcePatterns, project);
var filesWithRewrittenDirectives = [];
info('Found', sourceFiles.length, 'files');
sourceFiles.forEach(function (sourceFile, i) {
try {
var hasChanged_1 = false;
var importDeclarations = sourceFile.getImportDeclarations();
var imports_1 = {};
var rewrittenImports_1 = [];
var rewrittenDirectives_1 = [];
sourceFile.getPathReferenceDirectives().forEach(function (directive) {
rewrittenDirectives_1.push("/// <reference path=\"" + directive.getText() + "\" />");
});
sourceFile.getTypeReferenceDirectives().forEach(function (directive) {
rewrittenDirectives_1.push("/// <reference type=\"" + directive.getText() + "\" />");
});
sourceFile.getLibReferenceDirectives().forEach(function (directive) {
rewrittenDirectives_1.push("/// <reference lib=\"" + directive.getText() + "\" />");
});
/** import Default, { named1, named2 as alias } from './file' */
importDeclarations.forEach(function (importDeclaration) {
/** Default */
var defaultImport = importDeclaration.getDefaultImport();
/** { named1, named2 as alias } */
var namedImports = importDeclaration.getNamedImports();
/** eg './file' or 'some-dependency' */
var modulePath = importDeclaration.getModuleSpecifierValue();
imports_1[modulePath] = imports_1[modulePath] || {
codeImports: [],
defaultImport: '',
typeImports: []
};
if (defaultImport) {
imports_1[modulePath].defaultImport = defaultImport.getText();
hasChanged_1 = true;
}
namedImports.forEach(function (namedImport) {
var _a;
/** import { named2 as alias } */
var alias = (_a = namedImport.getAliasNode()) === null || _a === void 0 ? void 0 : _a.getText();
var definitions = namedImport.getNameNode().getDefinitions();
/** determine whether this import is a type or an implementation */
definitions.forEach(function (definition) {
var definitionName = definition.getName();
var finalName = alias ? definitionName + " as " + alias : definitionName;
var definitionKind = definition.getKind();
if (['type', 'interface'].includes(definitionKind)) {
hasChanged_1 = true;
imports_1[modulePath].typeImports.push(finalName);
}
else {
hasChanged_1 = true;
imports_1[modulePath].codeImports.push(finalName);
}
});
});
if (hasChanged_1) {
importDeclaration.remove();
}
});
// write new imports for those we've collected and removed
Object.entries(imports_1).forEach(function (_a) {
var _b = __read(_a, 2), identifier = _b[0], _c = _b[1], codeImports = _c.codeImports, defaultImport = _c.defaultImport, typeImports = _c.typeImports;
if (defaultImport && codeImports.length) {
rewrittenImports_1.push("import " + defaultImport + ", { " + codeImports.join(', ') + " } from '" + identifier + "'");
}
if (defaultImport && !codeImports.length) {
rewrittenImports_1.push("import " + defaultImport + " from '" + identifier + "'");
}
if (!defaultImport && codeImports.length) {
rewrittenImports_1.push("import { " + codeImports.join(', ') + " } from '" + identifier + "'");
}
if (typeImports.length) {
rewrittenImports_1.push("import type { " + typeImports.join(', ') + " } from '" + identifier + "'");
}
});
// nothing to do
if (rewrittenImports_1.length === 0) {
console.log(chalk_1["default"].gray('-', getRelativePath(sourceFile)));
return;
}
console.log(chalk_1["default"].green('✓', getRelativePath(sourceFile)));
if (rewrittenDirectives_1.length > 0) {
filesWithRewrittenDirectives.push(getRelativePath(sourceFile));
console.log(chalk_1["default"].yellow('! contains triple-slash directives'));
}
sourceFile.insertText(0, rewrittenImports_1.join(os_1.EOL) + os_1.EOL + os_1.EOL);
if (organiseImports !== false) {
sourceFile.organizeImports();
}
if (dryRun === true) {
console.log(sourceFile.getText());
}
else {
sourceFile.saveSync();
}
}
catch (err) {
console.log(chalk_1["default"].red('×', getRelativePath(sourceFile)));
}
});
console.log('');
console.log(chalk_1["default"].bgGreen.black(' Complete '));
console.log('');
if (filesWithRewrittenDirectives.length > 0) {
console.log(chalk_1["default"].yellow(("\n* Moving triple-slash directives such as /// <reference lib=\"webworker\" /> back\n to the top of the file is not yet supported. If you know how to do this using\n https://ts-morph.com please open a PR or otherwise let me know.\n\n https://github.com/JamieMason/ts-import-types-cli/pulls\n\n Unfortunately until then, the following files will need their triple-slash\n directives manually moving back to the top of the file:\n" + filesWithRewrittenDirectives.map(function (filePath) { return "\n - " + filePath; }).join('') + "\n").trim()));
}
}
exports.tsImportTypes = tsImportTypes;