typescript-import-refactoring-burguer
Version:
While VSCode haven't the auto reimport files on folder change or renaming for refactoring situations, this script will help
161 lines (140 loc) • 5.12 kB
JavaScript
/**
* Exterme Go Horse TypeScript import refactoring lib
*
* TODO LIST
* - Generate import path from classes that was not imported in file
* - Convert this to TypeScript code and remove the 'Extreme Go Horse' code
* - Write unit tests to each situation of file importation or refactoring
* - Convert it into a VSCode plugin
* - Publish this in npm
* - Write code to cover importation from node_modules
*/
const fs = require('fs');
const args = process.argv.splice(2);
const config = { dir: process.cwd() };
args.forEach(arg => {
if (/^--dir=.*$/.test(arg)) {
let subdir = arg.replace(/^.*=/, '');
if (subdir === '.') {
subdir = '';
}
config.dir = `${process.cwd()}\\${subdir}`;
}
});
const exportMapByClass = {};
const exportMapByPath = {};
function Directory(path) {
this.path = path;
this.content = [];
this.forEach = function(calle){
this.content.forEach((f) => calle(f));
}
// constructor
fs.readdirSync(this.path).forEach(path => {
const fullpath = `${this.path}\\${path}`;
if (fs.lstatSync(fullpath).isDirectory()) {
this.content.push(new Directory(fullpath));
} else {
if (/\.ts$/.test(fullpath)) {
this.content.push(new TSFile(fullpath));
}
}
});
}
function TSFile(path) {
this.path = path.replace(/\/|(\\\\)|\\/g, '/');
this.content = String(fs.readFileSync(this.path));
this.exports = [];
this.imports = {};
exportMapByPath[this.path] = this;
(this.content.match(/import.*["'].*["'];?/g) || []).forEach(_import => {
_import = new TSFileImport(this.path, _import);
this.imports[_import.from] = _import;
});
(this.content.match(/export\s+(class|enum|type|interface)\s+[^\s]*\s*{/g) || []).forEach(match => {
var thisClass = match.replace(/^export\s+(class|enum|type|interface)\s+|\s*{$/g, '');
this.exports.push(thisClass);
var arr = exportMapByClass[thisClass] || [];
arr.push(this);
exportMapByClass[thisClass] = arr;
});
}
function TSFileImport(path, _import) {
var parentPath = path.replace(/[\/\\][^\/\\]*$/, '');
this._import = _import;
this.classes = _import.replace(/^import {|}.*$|\s/g, '').trim().split(',');
this.from = fundirPaths(parentPath, _import.replace(/^[^'"]*|['"]\.?|;/g, ''))+'.ts';
this.fromNodeModules = !_import.match(/['"](\.|app\/)/);
}
function pathGenerator(importer, importing) {
importer = importer.replace(/\/|(\\\\)|\\/g, '/').replace(/\/[^\/]*\.ts$/, '').split('/');
importing = importing.replace(/\/|(\\\\)|\\/g, '/').split('/');
var length = importer.length;
var importFinal = '';
for (let i = 0; i < importer.length; i++) {
if (importer[i] !== importing[i]) {
length = i;
break;
}
}
var relativeImport = importer.splice(length);
importing = importing.splice(length);
if (relativeImport.length == 0) {
importFinal = './';
} else {
relativeImport.forEach(() => importFinal += '../');
}
return importFinal + importing.join('/').replace(/\.ts$/, '');
}
function fundirPaths(basePath, restoPath) {
basePath = basePath.replace(/\/|(\\\\)|\\/g, '/').split('/');
restoPath = restoPath.replace(/\/|(\\\\)|\\/g, '/').split('/');
let quantosRetorna = 0;
restoPath.forEach((resto) => {
if (resto) {
if (resto == '..') {
basePath.pop();
} else {
basePath.push(resto);
}
}
});
return basePath.join('/');
}
(function reviewCode(project){
project.forEach(item => {
if (item instanceof Directory) {
reviewCode(item);
} else {
Object.keys(item.imports).forEach(importation => {
if (!item.imports[importation].fromNodeModules) {
if (!exportMapByPath[importation]) {
var pathAntigoDaClasse = null, naoUsar = false;
item.imports[importation].classes.forEach((cls) => {
if (!pathAntigoDaClasse) {
pathAntigoDaClasse = exportMapByClass[cls];
} else if (pathAntigoDaClasse != exportMapByClass[cls]) {
console.error(`Won't import the class ${cls} because it more than one path`);
naoUsar = true;
}
});
if (!pathAntigoDaClasse) {
naoUsar = true;}
if (pathAntigoDaClasse && pathAntigoDaClasse.length > 1) {
naoUsar = true;
console.error(`A class has more than one path, the refactorer will not reimport. One of these classes: ${pathAntigoDaClasse[0].exports}`);
}
if (!naoUsar) {
var newImport = item.imports[importation]._import.replace(/from.*$/, `from '${pathGenerator(item.path, pathAntigoDaClasse[0].path)}';`);
item.content = item.content.replace(item.imports[importation]._import, newImport);
if (item.imports[importation]._import != newImport) {
console.log(`Problem found on "${item.imports[importation]._import}", correction applied "${newImport}"`);
fs.writeFileSync(item.path, item.content);
}
}
}
}
});
}
});
})(new Directory(config.dir));