Created
October 8, 2021 04:21
-
-
Save zthxxx/66a7c7e2b96c0001ec9a8f6a9c4cc046 to your computer and use it in GitHub Desktop.
replace import / import() / export from path
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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