codemods: implement core-imports codemod
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -26,9 +26,11 @@
|
||||
"dependencies": {
|
||||
"@backstage/cli-common": "0.1.1",
|
||||
"chalk": "^4.0.0",
|
||||
"jscodeshift": "^0.12.0"
|
||||
"jscodeshift": "^0.12.0",
|
||||
"jscodeshift-add-imports": "^1.0.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jscodeshift": "^0.11.0",
|
||||
"@types/node": "^14.14.32",
|
||||
"commander": "^6.1.0",
|
||||
"ts-node": "^9.1.1"
|
||||
|
||||
@@ -13,4 +13,74 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
console.log('hello');
|
||||
|
||||
const addImports = require('jscodeshift-add-imports');
|
||||
const { resolve: resolvePath } = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
function findExports(packageName) {
|
||||
const packagePath = require.resolve(`${packageName}/package.json`);
|
||||
const typesPath = resolvePath(packagePath, '../dist/index.d.ts');
|
||||
const content = fs.readFileSync(typesPath, 'utf8');
|
||||
const [, exportSymbols] = content.match(/export \{ (.*) \};/);
|
||||
return exportSymbols
|
||||
.split(', ')
|
||||
.map(exported => exported.match(/.* as (.*)/)?.[1] || exported);
|
||||
}
|
||||
|
||||
const symbolTable = {
|
||||
'@backstage/core-app-api': findExports('@backstage/core-app-api'),
|
||||
'@backstage/core-components': findExports('@backstage/core-components'),
|
||||
'@backstage/core-plugin-api': findExports('@backstage/core-plugin-api'),
|
||||
};
|
||||
|
||||
const reverseSymbolTable = Object.entries(symbolTable).reduce(
|
||||
(table, [pkg, symbols]) => {
|
||||
for (const symbol of symbols) {
|
||||
table[symbol] = pkg;
|
||||
}
|
||||
return table;
|
||||
},
|
||||
{},
|
||||
);
|
||||
|
||||
module.exports = (file, /** @type {import('jscodeshift').API} */ api) => {
|
||||
const j = api.jscodeshift;
|
||||
const root = j(file.source);
|
||||
|
||||
// Find all import statements of @backstage/core
|
||||
const imports = root.find(j.ImportDeclaration, {
|
||||
source: {
|
||||
value: '@backstage/core',
|
||||
},
|
||||
});
|
||||
|
||||
// Then loop through all the import statement and collects each imported symbol
|
||||
const importedSymbols = imports.nodes().flatMap(node =>
|
||||
(node.specifiers || []).flatMap(specifier => ({
|
||||
name: specifier.imported.name, // The symbol we're importing
|
||||
local: specifier.local.name, // The local name, usually this is the same
|
||||
})),
|
||||
);
|
||||
|
||||
// Now that we gathered all the imports we want to add, we get rid of the old one
|
||||
imports.remove();
|
||||
|
||||
// The convert the imports into actual import statements
|
||||
const newImportStatements = importedSymbols.map(({ name, local }) => {
|
||||
const targetPackage = reverseSymbolTable[name];
|
||||
if (!targetPackage) {
|
||||
throw new Error(`No target package found for import of ${name}`);
|
||||
}
|
||||
|
||||
return j.importDeclaration(
|
||||
[j.importSpecifier(j.identifier(name), j.identifier(local))],
|
||||
j.literal(targetPackage),
|
||||
);
|
||||
});
|
||||
|
||||
// And add the new imports. `addImports` will take care of resolving duplicates
|
||||
addImports(root, newImportStatements);
|
||||
|
||||
return root.toSource();
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user