@o3r/schematics
Version:
Schematics module of the Otter framework
91 lines • 5.26 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.updateImportsInFile = updateImportsInFile;
const ast_utils_1 = require("@schematics/angular/utility/ast-utils");
const ts = require("typescript");
const escapeRegExp = (str) => str.replace(/[$()*+./?[\\\]^{|}-]/g, '\\$&');
/**
* Update the imports of a given file according to replace mapping
* @param logger Logger to report messages
* @param tree File System tree
* @param sourceFile Source file to analyze
* @param importsRegexp Regexp of the imports to replace
* @param renamePackagesRegexp Regexp of the packages to replace
* @param mapImports Map of the import to replace
* @param renamedPackages Map of the import package to replace
*/
function updateImportsInFile(logger, tree, sourceFile, importsRegexp, renamePackagesRegexp, mapImports = {}, renamedPackages = {}) {
const oldImportedSymbolsPerPackage = {};
const unResolvedImports = [];
const importNodes = [];
// First we look for all imports lines targeting an Otter package for which we know a mapping
(0, ast_utils_1.findNodes)(sourceFile, ts.SyntaxKind.ImportDeclaration).map((nodeImp) => {
const imp = nodeImp;
const importFrom = imp.moduleSpecifier.getText().replace(/["']/g, '');
const renamePackageMatch = importFrom.match(renamePackagesRegexp);
const otterPackage = renamePackageMatch?.[0] || importFrom.match(importsRegexp)?.[0];
// If the import matched an Otter package
if (otterPackage) {
if (!oldImportedSymbolsPerPackage[otterPackage]) {
oldImportedSymbolsPerPackage[otterPackage] = [];
}
// We store the import line to be able to remove it afterwards
importNodes.push(imp);
// We retrieve all the symbols listed in the import statement
const namedImport = imp.importClause?.namedBindings;
const isTypeOnlyImport = !!imp.importClause && ts.isTypeOnlyImportDeclaration(imp.importClause);
const imports = namedImport && ts.isNamedImports(namedImport)
? namedImport.elements.map((element) => ({ symbol: element.getText(), isTypeOnlyImport, location: importFrom }))
: [];
// And associate them to the Otter package
oldImportedSymbolsPerPackage[otterPackage].push(...imports);
}
});
// If did not capture any interesting import line, do nothing
if (importNodes.length === 0) {
return 0;
}
// Iterate over the imports and look into the renamed packages and into the map to see the import new module
// If no mapping is found, we keep the original import location
const resolvedImports = Object.entries(oldImportedSymbolsPerPackage).reduce((acc, [oldPackageName, importsFromOldPackage]) => {
importsFromOldPackage.forEach((importSymbol) => {
const newPackageNameImport = renamedPackages[oldPackageName]
? importSymbol.location.replace(oldPackageName, renamedPackages[oldPackageName])
: mapImports[oldPackageName]?.[importSymbol.symbol]?.newPackage;
const importFrom = newPackageNameImport || importSymbol.location;
if (!newPackageNameImport) {
unResolvedImports.push(importSymbol);
}
if (!acc[importFrom]) {
acc[importFrom] = [];
}
const newNameForExportedValue = mapImports[oldPackageName]?.[importSymbol.symbol]?.newValue;
acc[importFrom].push(`${importSymbol.isTypeOnlyImport ? 'type ' : ''}${newNameForExportedValue || importSymbol.symbol}`);
});
return acc;
}, {});
let fileContent = tree.readText(sourceFile.fileName);
// Remove captured imports
fileContent = fileContent.replace(new RegExp(`(${importNodes.map((node) => escapeRegExp(node.getText())).join('|')})[\\n\\r]*`, 'g'), '');
// Replace imported values
const valuesToReplace = Object.fromEntries(Object.values(mapImports).flatMap((mapImport) => Object.entries(mapImport)
.filter(([_, value]) => value.newValue)
.map(([key, value]) => [key, value.newValue])));
if (Object.keys(valuesToReplace).length > 0) {
const matcher = new RegExp(Object.keys(valuesToReplace).map((oldValue) => `\\b${escapeRegExp(oldValue)}\\b`).join('|'), 'g');
const replacer = (match) => valuesToReplace[match];
fileContent = fileContent.replace(matcher, replacer);
}
// Add the computed imports at the top of the file
fileContent = Object.entries(resolvedImports)
.map(([importFrom, imports]) => `import {${imports.join(', ')}} from '${importFrom}';`)
.join('\n') + '\n' + fileContent;
tree.overwrite(sourceFile.fileName, fileContent);
// Log details about imports for which we could not find an associated sub-entry
if (unResolvedImports.length > 0) {
logger.warn(`Some imports in file ${sourceFile.fileName} could not be resolved:`);
unResolvedImports.forEach((unResolvedImport) => logger.warn(` |-- symbol "${unResolvedImport.symbol}" from module "${unResolvedImport.location}"`));
}
return unResolvedImports.length;
}
//# sourceMappingURL=update-imports.js.map