-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(codemod): Add antd-to-oceanbase-design, obui-to-oceanbase-design…
… and techui-to-oceanbase-ui transformer
- Loading branch information
1 parent
8ac1f06
commit 23b8697
Showing
25 changed files
with
6,227 additions
and
13,120 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# OceanBase Design Codemod | ||
|
||
A collection of codemod scripts that help migrate to OceanBase Design using [jscodeshift](https://github.com/facebook/jscodeshift) and [postcss](https://github.com/postcss/postcss).(Inspired by [@oceanbase/codemod](https://github.com/ant-design/codemod-v5)) | ||
|
||
[![NPM version](https://img.shields.io/npm/v/@oceanbase/codemod.svg?style=flat)](https://npmjs.org/package/@oceanbase/codemod) [![NPM downloads](http://img.shields.io/npm/dm/@oceanbase/codemod.svg?style=flat)](https://npmjs.org/package/@oceanbase/codemod) [![Github Action](https://github.com/oceanbase/design/actions/workflows/ci.yml/badge.svg)](https://github.com/oceanbase/design/actions/workflows/ci.yml) | ||
|
||
## Usage | ||
|
||
Before run codemod scripts, you'd better make sure to commit your local git changes firstly. | ||
|
||
```shell | ||
# Run directly through npx | ||
npx -p @oceanbase/codemod codemod src | ||
|
||
# Or run directly through pnpm | ||
pnpm --package=@oceanbase/codemod dlx codemod src | ||
``` |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
{ | ||
"name": "@oceanbase/codemod", | ||
"version": "0.1.0", | ||
"description": "Codemod for OceanBase Design upgrade", | ||
"keywords": [ | ||
"oceanbase", | ||
"oceanbase design", | ||
"codemod" | ||
], | ||
"homepage": "https://github.com/oceanbase/oceanbase-design/packages/codemod", | ||
"repository": { | ||
"type": "git", | ||
"url": "[email protected]:oceanbase/design.git" | ||
}, | ||
"publishConfig": { | ||
"registry": "https://registry.npmjs.org", | ||
"access": "public" | ||
}, | ||
"bin": { | ||
"codemod": "./bin/codemod.js" | ||
}, | ||
"scripts": { | ||
"build": "father build" | ||
}, | ||
"dependencies": { | ||
"chalk": "^3.0.0", | ||
"find-up": "^4.1.0", | ||
"glob": "^8.0.3", | ||
"is-git-clean": "^1.1.0", | ||
"jscodeshift": "^0.14.0", | ||
"lodash": "^4.17.15", | ||
"read-pkg-up": "^9.1.0", | ||
"semver": "^7.1.3", | ||
"update-check": "^1.5.3", | ||
"yargs-parser": "^21.1.1" | ||
}, | ||
"devDependencies": { | ||
"@types/jest": "^29.2.3", | ||
"@types/jscodeshift": "^0.11.5", | ||
"enzyme": "^3.0.0", | ||
"enzyme-to-json": "^3.4.0" | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
{ | ||
"sourceType": "module", | ||
"allowImportExportEverywhere": true, | ||
"allowReturnOutsideFunction": true, | ||
"startLine": 1, | ||
"tokens": true, | ||
"plugins": [ | ||
"jsx", | ||
"asyncGenerators", | ||
"bigInt", | ||
"classProperties", | ||
"classPrivateProperties", | ||
"classPrivateMethods", | ||
[ | ||
"decorators", | ||
{ | ||
"decoratorsBeforeExport": true | ||
} | ||
], | ||
"doExpressions", | ||
"dynamicImport", | ||
"exportDefaultFrom", | ||
"exportExtensions", | ||
"exportNamespaceFrom", | ||
"functionBind", | ||
"functionSent", | ||
"importMeta", | ||
"logicalAssignment", | ||
"nullishCoalescingOperator", | ||
"numericSeparator", | ||
"objectRestSpread", | ||
"optionalCatchBinding", | ||
"optionalChaining", | ||
[ | ||
"pipelineOperator", | ||
{ | ||
"proposal": "minimal" | ||
} | ||
], | ||
"throwExpressions", | ||
"typescript" | ||
] | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,284 @@ | ||
/* eslint no-console: 0 */ | ||
|
||
const path = require('path'); | ||
const fs = require('fs'); | ||
const os = require('os'); | ||
|
||
const _ = require('lodash'); | ||
const chalk = require('chalk'); | ||
const isGitClean = require('is-git-clean'); | ||
const updateCheck = require('update-check'); | ||
const findUp = require('find-up'); | ||
const semver = require('semver'); | ||
const { run: jscodeshift } = require('jscodeshift/src/Runner'); | ||
|
||
const pkg = require('../package.json'); | ||
const pkgUpgradeList = require('./upgrade-list'); | ||
const { getDependencies } = require('../transforms/utils/marker'); | ||
|
||
// jscodeshift codemod scripts dir | ||
const transformersDir = path.join(__dirname, '../transforms'); | ||
|
||
// jscodeshift bin#--ignore-config | ||
const ignoreConfig = path.join(__dirname, './codemod.ignore'); | ||
|
||
const transformers = [ | ||
'antd-to-oceanbase-design', | ||
'obui-to-oceanbase-design', | ||
'techui-to-oceanbase-ui', | ||
]; | ||
|
||
const dependencyProperties = [ | ||
'dependencies', | ||
'devDependencies', | ||
'clientDependencies', | ||
'isomorphicDependencies', | ||
'buildDependencies', | ||
]; | ||
|
||
async function ensureGitClean() { | ||
let clean = false; | ||
try { | ||
clean = await isGitClean(); | ||
} catch (err) { | ||
if (err && err.stderr && err.stderr.toLowerCase().includes('not a git repository')) { | ||
clean = true; | ||
} | ||
} | ||
|
||
if (!clean) { | ||
console.log(chalk.yellow('Sorry that there are still some git changes')); | ||
console.log('\n you must commit or stash them firstly'); | ||
process.exit(1); | ||
} | ||
} | ||
|
||
async function checkUpdates() { | ||
let update; | ||
try { | ||
update = await updateCheck(pkg); | ||
} catch (err) { | ||
console.log(chalk.yellow(`Failed to check for updates: ${err}`)); | ||
} | ||
|
||
if (update) { | ||
console.log(chalk.blue(`Latest version is ${update.latest}. Please update firstly`)); | ||
process.exit(1); | ||
} | ||
} | ||
|
||
function getMaxWorkers(options = {}) { | ||
// limit usage for cpus | ||
return options.cpus || Math.max(2, Math.ceil(os.cpus().length / 3)); | ||
} | ||
|
||
function getRunnerArgs( | ||
transformerPath, | ||
parser = 'babylon', // use babylon as default parser | ||
options = {} | ||
) { | ||
const args = { | ||
verbose: 2, | ||
// limit usage for cpus | ||
cpus: getMaxWorkers(options), | ||
// https://github.com/facebook/jscodeshift/blob/master/src/Runner.js#L255 | ||
// https://github.com/facebook/jscodeshift/blob/master/src/Worker.js#L50 | ||
babel: false, | ||
parser, | ||
// override default babylon parser config to enable `decorator-legacy` | ||
// https://github.com/facebook/jscodeshift/blob/master/parser/babylon.js | ||
parserConfig: require('./babylon.config.json'), | ||
extensions: ['tsx', 'ts', 'jsx', 'js'].join(','), | ||
transform: transformerPath, | ||
ignorePattern: '**/node_modules', | ||
ignoreConfig, | ||
}; | ||
|
||
return args; | ||
} | ||
|
||
async function run(filePath, args = {}) { | ||
for (const transformer of transformers) { | ||
await transform(transformer, 'babylon', filePath, args); | ||
} | ||
} | ||
|
||
async function transform(transformer, parser, filePath, options) { | ||
console.log(chalk.bgGreen.bold('Transform'), transformer); | ||
const transformerPath = path.join(transformersDir, `${transformer}.js`); | ||
|
||
const args = getRunnerArgs(transformerPath, parser, { | ||
...options, | ||
}); | ||
|
||
try { | ||
if (process.env.NODE_ENV === 'local') { | ||
console.log(`Running jscodeshift with: ${JSON.stringify(args)}`); | ||
} | ||
|
||
// js part | ||
await jscodeshift(transformerPath, [filePath], args); | ||
} catch (err) { | ||
console.error(err); | ||
if (process.env.NODE_ENV === 'local') { | ||
const errorLogFile = path.join(__dirname, './error.log'); | ||
fs.appendFileSync(errorLogFile, err); | ||
fs.appendFileSync(errorLogFile, '\n'); | ||
} | ||
} | ||
} | ||
|
||
async function upgradeDetect(targetDir, needOBCharts, needCompatible) { | ||
const result = []; | ||
const cwd = path.join(process.cwd(), targetDir); | ||
const { readPackageUp } = await import('read-pkg-up'); | ||
const closetPkgJson = await readPackageUp({ cwd }); | ||
|
||
let pkgJsonPath; | ||
if (!closetPkgJson) { | ||
pkgJsonPath = "we didn't find your package.json"; | ||
// unknown dependency property | ||
result.push(['install', '@oceanbase/design', pkgUpgradeList['@oceanbase/design']]); | ||
if (needOBCharts) { | ||
result.push(['install', '@oceanbase/charts', pkgUpgradeList['@oceanbase/charts'].version]); | ||
} | ||
|
||
if (needCompatible) { | ||
result.push([ | ||
'install', | ||
'@ant-design/compatible', | ||
pkgUpgradeList['@ant-design/compatible'].version, | ||
]); | ||
} | ||
} else { | ||
const { packageJson } = closetPkgJson; | ||
pkgJsonPath = closetPkgJson.path; | ||
|
||
// dependencies must be installed or upgraded with correct version | ||
const mustInstallOrUpgradeDeps = ['@oceanbase/design', '@oceanbase/icons']; | ||
if (needOBCharts) { | ||
mustInstallOrUpgradeDeps.push('@oceanbase/charts'); | ||
} | ||
if (needCompatible) { | ||
mustInstallOrUpgradeDeps.push('@ant-design/compatible'); | ||
} | ||
|
||
// handle mustInstallOrUpgradeDeps | ||
mustInstallOrUpgradeDeps.forEach(depName => { | ||
let hasDependency = false; | ||
const expectVersion = pkgUpgradeList[depName].version; | ||
// const upgradePkgDescription = pkgUpgradeList[depName].description; | ||
dependencyProperties.forEach(property => { | ||
const versionRange = _.get(packageJson, `${property}.${depName}`); | ||
// mark dependency installment state | ||
hasDependency = hasDependency || !!versionRange; | ||
// no dependency or improper version dependency | ||
if (versionRange && !semver.satisfies(semver.minVersion(versionRange), expectVersion)) { | ||
result.push(['update', depName, expectVersion, property]); | ||
} | ||
}); | ||
if (!hasDependency) { | ||
// unknown dependency property | ||
result.push(['install', depName, pkgUpgradeList[depName].version]); | ||
} | ||
}); | ||
|
||
// dependencies must be upgraded to correct version | ||
const mustUpgradeDeps = _.without(Object.keys(pkgUpgradeList), ...mustInstallOrUpgradeDeps); | ||
mustUpgradeDeps.forEach(depName => { | ||
dependencyProperties.forEach(property => { | ||
const expectVersion = pkgUpgradeList[depName].version; | ||
const versionRange = _.get(packageJson, `${property}.${depName}`); | ||
/** | ||
* we may have dependencies in `package.json` | ||
* make sure that they can `work well` with `oceanbase design system` | ||
* so we check dependency's version here | ||
*/ | ||
if (versionRange && !semver.satisfies(semver.minVersion(versionRange), expectVersion)) { | ||
result.push(['update', depName, expectVersion, property]); | ||
} | ||
}); | ||
}); | ||
} | ||
|
||
if (!result.length) { | ||
console.log(chalk.green('Checking passed')); | ||
return; | ||
} | ||
|
||
console.log( | ||
chalk.yellow( | ||
"It's recommended to install or upgrade these dependencies to ensure working well with oceanbase design system\n" | ||
) | ||
); | ||
console.log(`> package.json file: ${pkgJsonPath} \n`); | ||
const dependencies = result.map(([operateType, depName, expectVersion, dependencyProperty]) => | ||
[ | ||
_.capitalize(operateType), | ||
`${depName}${expectVersion}`, | ||
dependencyProperty ? `in ${dependencyProperty}` : '', | ||
].join(' ') | ||
); | ||
|
||
console.log(dependencies.map(n => `* ${n}`).join('\n')); | ||
} | ||
|
||
/** | ||
* options | ||
* --force // force skip git checking (dangerously) | ||
* --cpus=1 // specify cpus cores to use | ||
*/ | ||
|
||
async function bootstrap() { | ||
const dir = process.argv[2]; | ||
// eslint-disable-next-line global-require | ||
const args = require('yargs-parser')(process.argv.slice(3)); | ||
if (process.env.NODE_ENV !== 'local') { | ||
// check for updates | ||
await checkUpdates(); | ||
// check for git status | ||
if (!args.force) { | ||
await ensureGitClean(); | ||
} else { | ||
console.log( | ||
Array(3) | ||
.fill(1) | ||
.map(() => | ||
chalk.yellow('WARNING: You are trying to skip git status checking, please be careful') | ||
) | ||
.join('\n') | ||
); | ||
} | ||
} | ||
|
||
// check for `path` | ||
if (!dir || !fs.existsSync(dir)) { | ||
console.log(chalk.yellow('Invalid dir:', dir, ', please pass a valid dir')); | ||
process.exit(1); | ||
} | ||
|
||
await run(dir, args); | ||
|
||
try { | ||
console.log('----------- dependencies alert -----------\n'); | ||
const depsList = await getDependencies(); | ||
await upgradeDetect( | ||
dir, | ||
depsList.includes('@ant-design/pro-layout'), | ||
depsList.includes('@ant-design/compatible') | ||
); | ||
} catch (err) { | ||
console.log('skip summary due to', err); | ||
} finally { | ||
console.log(`\n----------- Thanks for using @ant-design/codemod ${pkg.version} -----------`); | ||
} | ||
} | ||
|
||
module.exports = { | ||
bootstrap, | ||
ensureGitClean, | ||
transform, | ||
run, | ||
getRunnerArgs, | ||
checkUpdates, | ||
}; |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
node_modules | ||
*.css | ||
*.json | ||
*.less | ||
*.sass | ||
*.scss | ||
.umi |
Oops, something went wrong.