Skip to content

Instantly share code, notes, and snippets.

@ds300
Last active September 6, 2023 11:18
Show Gist options
  • Save ds300/f6177171ac673f98f6028799563a06db to your computer and use it in GitHub Desktop.
Save ds300/f6177171ac673f98f6028799563a06db to your computer and use it in GitHub Desktop.
Add .js, .mjs, or .cjs file extensions to imports/exports in (transpiled) ESM files
import { existsSync, readFileSync, statSync, writeFileSync } from 'fs'
import glob from 'glob'
import path from 'path'
import { parse, print, visit } from 'recast'
const extensions = ['.js', '.mjs', '.cjs']
function resolveRelativePath(importingFile: string, relativePath: string) {
if (!relativePath.startsWith('.')) {
return relativePath
}
const containingDir = path.dirname(importingFile)
if (
existsSync(path.join(containingDir, relativePath)) &&
!statSync(path.join(containingDir, relativePath)).isDirectory()
) {
// if the file already exists, e.g. .css files, just use it
return relativePath
}
// strip the file extension if applicable
relativePath.replace(/\.(m|c)?js$/, '')
for (const extension of extensions) {
if (relativePath.endsWith(extension)) {
return relativePath
} else {
let candidate = `${relativePath}${extension}`
if (existsSync(path.join(containingDir, candidate))) {
return candidate
}
candidate = `${relativePath}/index${extension}`
if (existsSync(path.join(containingDir, candidate))) {
return candidate
}
}
}
throw new Error(`Could not resolve relative path ${relativePath} from ${importingFile}`)
}
export function addJsExtensions(distDir: string) {
for (const file of glob.sync(path.join(distDir, '**/*.{mjs,cjs,js}'))) {
const code = parse(readFileSync(file, 'utf8'), { parser: require('recast/parsers/typescript') })
visit(code, {
visitImportDeclaration(path) {
path.value.source.value = resolveRelativePath(file, path.value.source.value)
return false
},
visitExportAllDeclaration(path) {
path.value.source.value = resolveRelativePath(file, path.value.source.value)
return false
},
visitExportNamedDeclaration(path) {
if (path.value.source) {
path.value.source.value = resolveRelativePath(file, path.value.source.value)
}
return false
},
})
writeFileSync(file, print(code).code)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment