From d73ce9e4ae7deb6e73e14aade0ba96adc065cb3f Mon Sep 17 00:00:00 2001 From: dengfuping Date: Sat, 7 Oct 2023 21:37:15 +0800 Subject: [PATCH] feat(codemod): getTableData => useTableData for util --- packages/codemod/README.md | 16 ++-- .../getTableData.input.js | 28 ++++++ .../getTableData.output.js | 28 ++++++ .../obutil-to-oceanbase-util.test.ts | 2 +- .../transforms/obutil-to-oceanbase-util.js | 9 ++ .../transforms/utils/import-component.js | 33 +++++-- packages/util/src/hooks/index.ts | 94 +------------------ packages/util/src/hooks/useTableData.ts | 92 ++++++++++++++++++ 8 files changed, 195 insertions(+), 107 deletions(-) create mode 100644 packages/codemod/transforms/__testfixtures__/obutil-to-oceanbase-util/getTableData.input.js create mode 100644 packages/codemod/transforms/__testfixtures__/obutil-to-oceanbase-util/getTableData.output.js create mode 100644 packages/util/src/hooks/useTableData.ts diff --git a/packages/codemod/README.md b/packages/codemod/README.md index 99e2c739b..16d5efc11 100644 --- a/packages/codemod/README.md +++ b/packages/codemod/README.md @@ -17,7 +17,7 @@ npx -p @oceanbase/codemod codemod src ### `antd-to-oceanbase-design` -import components and typs from `antd` and `@alipay/bigfish/antd` to `@oceanbase/design`. +import components and types from `antd` and `@alipay/bigfish/antd` to `@oceanbase/design`. ```diff import React from 'react'; @@ -43,7 +43,7 @@ import components and typs from `antd` and `@alipay/bigfish/antd` to `@oceanbase ### `obui-to-oceanbase-design-and-ui` -import components and typs from `antd` to `@oceanbase/design` and `@oceanbase/ui`. +import components and types from `antd` to `@oceanbase/design` and `@oceanbase/ui`. ```diff import React from 'react'; @@ -86,7 +86,7 @@ import `PageContainer` from `@alipay/tech-ui` to `@ant-design/pro-components` an ### `antd-and-ob-charts-to-oceanbase-charts` -import components and typs from `@ant-design/charts` and `@alipay/ob-charts` to `@oceanbase/charts`. +import components and types from `@ant-design/charts` and `@alipay/ob-charts` to `@oceanbase/charts`. ```diff import React from 'react'; @@ -118,15 +118,17 @@ import components and typs from `@ant-design/charts` and `@alipay/ob-charts` to ### `obutil-to-oceanbase-util` -import components and typs from `@alipay/ob-util` to `@oceanbase/util`. +import utils and hooks from `@alipay/ob-util` to `@oceanbase/util`. Additionally, it will rename `getTableData` to `useTableData` to follow hooks naming conventions. ```diff import React from 'react'; -- import { isNullValue, sortByNumber } from '@alipay/ob-util'; -+ import { isNullValue, sortByNumber } from '@oceanbase/util'; +- import { isNullValue, sortByNumber, getTableData } from '@alipay/ob-util'; ++ import { isNullValue, sortByNumber, useTableData } from '@oceanbase/util'; const Demo = () => { - return
; +- const { tableProps } = getTableData(fn, {}); ++ const { tableProps } = useTableData(fn, {}); + return
; }; export default Demo; diff --git a/packages/codemod/transforms/__testfixtures__/obutil-to-oceanbase-util/getTableData.input.js b/packages/codemod/transforms/__testfixtures__/obutil-to-oceanbase-util/getTableData.input.js new file mode 100644 index 000000000..f6b106efa --- /dev/null +++ b/packages/codemod/transforms/__testfixtures__/obutil-to-oceanbase-util/getTableData.input.js @@ -0,0 +1,28 @@ +import React from 'react'; +import { getTableData } from '@alipay/ob-util'; + +const Demo = () => { + const { tableProps, refresh } = getTableData({ + fn: getClusters, + params: { + configName, + }, + refreshDeps: [], + options: { + pagePropName: 'pageNo', + sizePropName: 'pageSize', + formatResult: (res: any) => { + const { data, pageNo, pageSize, total } = res || {}; + return { + list: data || [], + current: pageNo, + pageSize, + total, + }; + }, + }, + }); + return
; +}; + +export default Demo; diff --git a/packages/codemod/transforms/__testfixtures__/obutil-to-oceanbase-util/getTableData.output.js b/packages/codemod/transforms/__testfixtures__/obutil-to-oceanbase-util/getTableData.output.js new file mode 100644 index 000000000..837c159c2 --- /dev/null +++ b/packages/codemod/transforms/__testfixtures__/obutil-to-oceanbase-util/getTableData.output.js @@ -0,0 +1,28 @@ +import React from 'react'; +import { useTableData } from '@oceanbase/util'; + +const Demo = () => { + const { tableProps, refresh } = useTableData({ + fn: getClusters, + params: { + configName, + }, + refreshDeps: [], + options: { + pagePropName: 'pageNo', + sizePropName: 'pageSize', + formatResult: (res: any) => { + const { data, pageNo, pageSize, total } = res || {}; + return { + list: data || [], + current: pageNo, + pageSize, + total, + }; + }, + }, + }); + return
; +}; + +export default Demo; diff --git a/packages/codemod/transforms/__tests__/obutil-to-oceanbase-util.test.ts b/packages/codemod/transforms/__tests__/obutil-to-oceanbase-util.test.ts index 0221437c2..7afa170cf 100644 --- a/packages/codemod/transforms/__tests__/obutil-to-oceanbase-util.test.ts +++ b/packages/codemod/transforms/__tests__/obutil-to-oceanbase-util.test.ts @@ -1,7 +1,7 @@ import { defineTest } from 'jscodeshift/src/testUtils'; const testUnit = 'obutil-to-oceanbase-util'; -const tests = ['obutil']; +const tests = ['obutil', 'getTableData']; describe(testUnit, () => { tests.forEach(test => diff --git a/packages/codemod/transforms/obutil-to-oceanbase-util.js b/packages/codemod/transforms/obutil-to-oceanbase-util.js index 65317fb36..2ced5a722 100644 --- a/packages/codemod/transforms/obutil-to-oceanbase-util.js +++ b/packages/codemod/transforms/obutil-to-oceanbase-util.js @@ -5,6 +5,15 @@ module.exports = (file, api, options) => { ...options, fromPkgNames: '@alipay/ob-util', toPkgList: [ + { + name: '@oceanbase/util', + components: [ + { + // rename + getTableData: 'useTableData', + }, + ], + }, { name: '@oceanbase/util', }, diff --git a/packages/codemod/transforms/utils/import-component.js b/packages/codemod/transforms/utils/import-component.js index 4d82cf1ec..06cb5188f 100644 --- a/packages/codemod/transforms/utils/import-component.js +++ b/packages/codemod/transforms/utils/import-component.js @@ -1,6 +1,8 @@ const { addSubmoduleImport, removeEmptyModuleImport, parseStrToArray } = require('./index'); const { markDependency } = require('./marker'); const { printOptions } = require('./config'); +const { isPlainObject } = require('lodash'); +const { flatten } = require('lodash'); function importComponent(j, root, options) { const { fromPkgNames, toPkgList } = options; @@ -15,11 +17,15 @@ function importComponent(j, root, options) { ); if (fromPkgName) { path.value.specifiers.forEach(specifier => { - const toPkgByComponents = toPkgList.find(toPkg => - toPkg.components?.includes(specifier.imported.name) + const toPkgByComponents = toPkgList.find( + toPkg => + toPkg.components?.includes(specifier.imported.name) || + toPkg.components?.find(component => component[specifier.imported.name]) ); - const toPkgByTypes = toPkgList.find(toPkg => - toPkg.types?.includes(specifier.imported.name) + const toPkgByTypes = toPkgList.find( + toPkg => + toPkg.types?.includes(specifier.imported.name) || + toPkg.types?.find(type => type[specifier.imported.name]) ); const toPkg = toPkgByComponents || toPkgByTypes; if (toPkg) { @@ -31,13 +37,28 @@ function importComponent(j, root, options) { path.value.specifiers = path.value.specifiers.filter( item => !item.imported || item.imported.name !== specifier.imported.name ); - // add new imports + const renameComponent = toPkg.components?.find( + component => component[specifier.imported.name] + ); + const renameType = toPkg.types?.find(type => type[specifier.imported.name]); + const rename = renameComponent || renameType; + // add and rename new imports addSubmoduleImport(j, root, { moduleName: toPkg.name, - importedName: specifier.imported.name, + importedName: rename ? rename[specifier.imported.name] : specifier.imported.name, importKind: toPkgByTypes ? 'type' : 'value', after: fromPkgName, }); + // rename used part + if (rename) { + root + .find(j.Identifier, { + name: specifier.imported.name, + }) + .forEach(path => { + path.node.name = rename[specifier.imported.name]; + }); + } } markDependency(toPkg.name); } diff --git a/packages/util/src/hooks/index.ts b/packages/util/src/hooks/index.ts index 2f874c2a0..66ad570fe 100644 --- a/packages/util/src/hooks/index.ts +++ b/packages/util/src/hooks/index.ts @@ -1,95 +1,3 @@ -import { some, isNil, noop, omitBy } from 'lodash'; -import { useAntdTable } from 'ahooks'; -import { DEFAULT_LIST_DATA } from '../constant'; -import { isNullValue } from '../util'; - -const sortOrderMap = { - ascend: 'asc', - descend: 'desc', -}; - -const defaultAsnycFnOfUseTableData = () => { - const promise = new Promise(resolve => { - resolve({ - tableProps: { - dataSource: [], - loading: false, - pagination: { - total: 0, - current: 1, - pageSize: 10, - }, - }, - refresh: noop, - search: { - changeType: noop, - submit: noop, - reset: noop, - }, - }); - }); - promise.then(data => { - return data; - }); - return promise; -}; - -/** - * 获取表格数据,内置后端分页、筛选和排序的请求逻辑,同时支持条件请求 - * TODO: 后续需要补全 TS 类型定义 - */ -export function useTableData({ fn, params = {}, condition = [], refreshDeps = [], options = {} }) { - const { pagePropName = 'page', sizePropName = 'size', ...restOptions } = options as any; - const newOptions = { - formatResult: res => { - const { data } = (res || {}) as any; - // 接口请求出错时,后端返回的 res.data 可能为 undefined。避免前端解析错误导致页面崩溃,这里需要做健壮性处理 - const { page: { totalElements = 0 } = {}, contents = [] } = data || DEFAULT_LIST_DATA; - return { - total: totalElements, - list: contents, - }; - }, - refreshDeps, - ...restOptions, - }; - - const serviceFn = some(condition, item => isNullValue(item)) - ? defaultAsnycFnOfUseTableData - : ({ current, pageSize, sorter = {}, filters = {} }) => { - // eslint-disable-next-line - let newFilters = {} as any; - Object.keys(filters).forEach(key => { - // antd 4.x 的表格筛选,在筛选项为空时,对应字段为 null 值,为了适配这里调用 join 方法前需要做非空判断 - newFilters[key] = filters[key] && filters[key].join(','); - }); - // 对列表查询参数进行处理 - const newParams = omitBy( - { - [pagePropName]: current, - [sizePropName]: pageSize, - // @ts-ignore - sort: sorter.order - ? // @ts-ignore - `${sorter.field},${sortOrderMap[sorter.order as 'ascend' | 'descend']}` - : null, - ...newFilters, - ...params, - }, - value => isNil(value) || value === '' // 将空值剔除 - ); - return fn(newParams); - }; - - const result = useAntdTable(serviceFn, newOptions); - if (result) { - // @ts-ignore - result.tableProps.pagination.showSizeChanger = true; - // @ts-ignore - result.tableProps.pagination.showTotal = (total: number) => `共 ${total} 条`; - } - return result; -} - +export { useTableData } from './useTableData'; export { useQuery } from './useQuery'; export { useScrollToPosition } from './useScrollToPosition'; diff --git a/packages/util/src/hooks/useTableData.ts b/packages/util/src/hooks/useTableData.ts new file mode 100644 index 000000000..460cc0da5 --- /dev/null +++ b/packages/util/src/hooks/useTableData.ts @@ -0,0 +1,92 @@ +import { some, isNil, noop, omitBy } from 'lodash'; +import { useAntdTable } from 'ahooks'; +import { DEFAULT_LIST_DATA } from '../constant'; +import { isNullValue } from '../util'; + +const sortOrderMap = { + ascend: 'asc', + descend: 'desc', +}; + +const defaultAsnycFnOfUseTableData = () => { + const promise = new Promise(resolve => { + resolve({ + tableProps: { + dataSource: [], + loading: false, + pagination: { + total: 0, + current: 1, + pageSize: 10, + }, + }, + refresh: noop, + search: { + changeType: noop, + submit: noop, + reset: noop, + }, + }); + }); + promise.then(data => { + return data; + }); + return promise; +}; + +/** + * 获取表格数据,内置后端分页、筛选和排序的请求逻辑,同时支持条件请求 + * TODO: 后续需要补全 TS 类型定义 + */ +export function useTableData({ fn, params = {}, condition = [], refreshDeps = [], options = {} }) { + const { pagePropName = 'page', sizePropName = 'size', ...restOptions } = options as any; + const newOptions = { + formatResult: res => { + const { data } = (res || {}) as any; + // 接口请求出错时,后端返回的 res.data 可能为 undefined。避免前端解析错误导致页面崩溃,这里需要做健壮性处理 + const { page: { totalElements = 0 } = {}, contents = [] } = data || DEFAULT_LIST_DATA; + return { + total: totalElements, + list: contents, + }; + }, + refreshDeps, + ...restOptions, + }; + + const serviceFn = some(condition, item => isNullValue(item)) + ? defaultAsnycFnOfUseTableData + : ({ current, pageSize, sorter = {}, filters = {} }) => { + // eslint-disable-next-line + let newFilters = {} as any; + Object.keys(filters).forEach(key => { + // antd 4.x 的表格筛选,在筛选项为空时,对应字段为 null 值,为了适配这里调用 join 方法前需要做非空判断 + newFilters[key] = filters[key] && filters[key].join(','); + }); + // 对列表查询参数进行处理 + const newParams = omitBy( + { + [pagePropName]: current, + [sizePropName]: pageSize, + // @ts-ignore + sort: sorter.order + ? // @ts-ignore + `${sorter.field},${sortOrderMap[sorter.order as 'ascend' | 'descend']}` + : null, + ...newFilters, + ...params, + }, + value => isNil(value) || value === '' // 将空值剔除 + ); + return fn(newParams); + }; + + const result = useAntdTable(serviceFn, newOptions); + if (result) { + // @ts-ignore + result.tableProps.pagination.showSizeChanger = true; + // @ts-ignore + result.tableProps.pagination.showTotal = (total: number) => `共 ${total} 条`; + } + return result; +}