Skip to content

Instantly share code, notes, and snippets.

@zthxxx
Created October 8, 2021 04:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zthxxx/66a7c7e2b96c0001ec9a8f6a9c4cc046 to your computer and use it in GitHub Desktop.
Save zthxxx/66a7c7e2b96c0001ec9a8f6a9c4cc046 to your computer and use it in GitHub Desktop.
replace import / import() / export from path
import {
namedTypes as types,
} from 'ast-types'
import type {
Options as RecastOptions,
} from 'recast'
import type {
Transform,
FileInfo,
API,
} from 'jscodeshift'
/**
* usage:
* $ npx jscodeshift --extensions=js,jsx,ts,tsx -t codemod-import-path.ts <source-dir>
*
* replace import / import() / export from path with `importReplaceMap` config
* examples:
* import xx, { xxx } from 'lodash' => import xx, { xxx } from 'lodash-es'
* import('lodash') => import('lodash-es')
* export * from 'lodash/file' => export * 'from lodash-es'
* export { xxx } from 'lodash/kkk' => export { xxx } from 'lodash-es'
*/
const importReplaceRules: ReplaceRule[] = [
[/^lodash$/, 'lodash-es'],
]
const ignoreSourcePaths: RegExp[] = [
/node_modules/,
/\.umi/,
/src\/components\/Common/,
]
type ReplaceRule = [RegExp | string, string]
type ImportExportDeclaration = (
| types.ImportDeclaration
| types.ImportExpression
| types.ExportAllDeclaration
| types.ExportNamedDeclaration
) & { source: types.StringLiteral }
export const transform: Transform = (fileInfo: FileInfo, api: API) => {
if (ignoreSourcePaths.some(ignorePath => ignorePath.test(fileInfo.path))) {
return
}
const { jscodeshift: j } = api
const root = j(fileInfo.source)
/**
* ast example see:
* https://astexplorer.net/#/gist/6f649c56fe3dd309f5ac4a78d33f1891/9d0ef45a530573976cda46d31ce3052cd7de6cd3
*/
const importDeclarations: ImportExportDeclaration[] = [
types.ImportDeclaration,
types.ImportExpression,
types.ExportAllDeclaration,
types.ExportNamedDeclaration,
]
.map(type => root.find(
type,
(node: ImportExportDeclaration) => findRuleMatch(importReplaceRules, node.source?.value),
))
.map(collection => collection.paths())
.flat()
.map(({ value }) => value as ImportExportDeclaration)
if (!importDeclarations.length) {
return
}
// mutable
importDeclarations.forEach((node) => {
const path = node.source.value
const [ruleTester, ruleReplace] = findRuleMatch(importReplaceRules, path)!
node.source.value = path.replace(ruleTester, ruleReplace)
})
return root.toSource(recastStyleOption)
}
const findRuleMatch = (rules: ReplaceRule[], path?: string): ReplaceRule | undefined => {
if (!path) return
return rules.find(
([rule]) => (
rule instanceof RegExp
? rule.test(path)
: path.startsWith(rule)
),
)
}
const recastStyleOption: RecastOptions = {
tabWidth: 2,
useTabs: false,
wrapColumn: 100,
quote: 'single',
trailingComma: true,
}
export const parser = 'tsx'
// default function will used in jscodeshift
export default transform
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment