Skip to content

Instantly share code, notes, and snippets.

@rigwild
Last active May 5, 2024 13:30
Show Gist options
  • Save rigwild/2be7c5ccb6d21ab01fc1c47e1f565518 to your computer and use it in GitHub Desktop.
Save rigwild/2be7c5ccb6d21ab01fc1c47e1f565518 to your computer and use it in GitHub Desktop.
Script to recursively convert all imports from a directory to ESM compatible imports with `.js` file extensions, will also replace directory imports with direct `/index.js` imports.
// @ts-check
/**
* This script is used to fix imports in the generated typechain types.
*
* The generated typechain types are not compatible with ESM imports.
* They use directory imports and imports without file extensions.
*
* Usage:
*
* npx hardhat compile
* node scripts/renameImportsForEsmSupport.js
*/
import * as fs from 'fs'
import * as path from 'path'
import * as url from 'url'
const __filename = url.fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
const directoryPath = path.join(__dirname, 'typechain-types')
const fixImports = filePath => {
console.log(`Fixing imports for file: ${filePath}`)
let data = fs.readFileSync(filePath, 'utf8')
const allMatches = data.match(/from "(\..*?)(?<!\.js)"/g)
if (!allMatches) return
// Try to add `.ts` to the import and check if it is a valid file
// If it is a valid file, append `.js` to the import
// else, append `/index.js` to the import
let result = data
for (const match of allMatches) {
const importPath = match.replace(/from ["'](.*?)(?<!\.js)["']/, '$1')
const tsPath = path.join(path.dirname(filePath), `${importPath}.ts`)
const jsPath = path.join(path.dirname(filePath), `${importPath}.js`)
const indexTsPath = path.join(path.dirname(filePath), `${importPath}/index.ts`)
const indexJsPath = path.join(path.dirname(filePath), `${importPath}/index.js`)
// console.log(` Checking: ${tsPath}`)
// console.log(` Checking: ${jsPath}`)
// console.log(` Checking: ${indexTsPath}`)
// console.log(` Checking: ${indexJsPath}`)
// Set the import path prefix (to make sure we don't have `././something.js`)
let importPathPrefix = './'
if (importPath.startsWith('./') || importPath.startsWith('../')) {
importPathPrefix = ''
}
// Fix the import
if (fs.existsSync(jsPath) || fs.existsSync(tsPath)) {
result = result.replace(match, `from "${importPathPrefix}${importPath}.js"`)
} else if (fs.existsSync(indexTsPath) || fs.existsSync(indexJsPath)) {
result = result.replace(match, `from "${importPathPrefix}${importPath}/index.js"`)
} else {
console.log(`Could not find file for import: ${match}`)
}
}
fs.writeFileSync(filePath, result, 'utf8')
}
const traverseDirectories = dirPath => {
fs.readdirSync(dirPath, { withFileTypes: true }).forEach(dirent => {
const fullPath = path.join(dirPath, dirent.name)
if (dirent.isDirectory()) {
traverseDirectories(fullPath)
} else if (dirent.isFile() && dirent.name.endsWith('.ts')) {
fixImports(fullPath)
}
})
}
console.log(`Fixing imports to be ESM compatible in: ${directoryPath}`)
traverseDirectories(directoryPath)
// fixImports(directoryPath + '/index.ts')
@rigwild
Copy link
Author

rigwild commented May 2, 2024

The script supports parent directory path traversal like from "../xxx" as well.

This works both for double " and single quotes ', but will generate double quotes imports ".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment