diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 23bcfc6f3..383dfd9c1 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -9,5 +9,119 @@ on: types: [opened, synchronize, reopened] jobs: - call-test-build: - uses: Tencent/tdesign/.github/workflows/test-build.yml@main + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: check_github_primary_email + run: | + log_emails=$(git log --pretty=format:"%ae %ce" -1) + if [[ ${log_emails} =~ 'tdesign@tencent.com' ]];then + echo "$log_emails 跳过验证" + exit 0 + fi + if [[ ${log_emails} =~ '@tencent.com' ]];then + echo "默认邮箱 $log_emails 校验非法,可以去 https://github.com/settings/emails 更改" + exit 2; + else + echo "邮箱 $log_emails 校验通过"; + fi + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + - name: check_local_email + run: | + log_emails=$(git log --pretty=format:"%ae %ce" -1) + if [[ ${log_emails} =~ 'tdesign@tencent.com' ]];then + echo "$log_emails 跳过验证" + exit 0 + fi + if [[ ${log_emails} =~ '@tencent.com' ]];then + echo "本地提交邮箱 $log_emails 校验非法,需要本地更改重新提交" + exit 2; + else + echo "邮箱 $log_emails 校验通过"; + fi + + test: + # needs: check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - uses: pnpm/action-setup@v4 + with: + version: 9 + - uses: actions/setup-node@v4 + with: + node-version: 18 + + - run: node script/migrate/migrateConfig.mjs + - run: pnpm install + - run: node script/migrate/migrateComponent.mjs + + - run: npm run lint + - run: npm run test + + site: + runs-on: ubuntu-latest + # needs: test + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - uses: pnpm/action-setup@v4 + with: + version: 9 + - uses: actions/setup-node@v4 + with: + node-version: 18 + + - run: node script/migrate/migrateConfig.mjs + - run: pnpm install + - run: node script/migrate/migrateComponent.mjs + + - name: Build site + run: npm run site:preview + + - run: | + zip -r _site.zip _site + + - name: upload _site artifact + uses: actions/upload-artifact@v4 + with: + name: _site + path: _site.zip + retention-days: 5 + + - name: Save PR number + if: ${{ always() }} + run: echo ${{ github.event.number }} > ./pr-id.txt + + - name: Upload PR number + if: ${{ always() }} + uses: actions/upload-artifact@v4 + with: + name: pr + path: ./pr-id.txt + + build: + runs-on: ubuntu-latest + # needs: build + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - uses: pnpm/action-setup@v4 + with: + version: 9 + - uses: actions/setup-node@v4 + with: + node-version: 18 + + - run: node script/migrate/migrateConfig.mjs + - run: pnpm install + - run: node script/migrate/migrateComponent.mjs + - name: Build + run: npm run build diff --git a/script/migrate/components/anchor.mjs b/script/migrate/components/anchor.mjs new file mode 100644 index 000000000..1d110ad1b --- /dev/null +++ b/script/migrate/components/anchor.mjs @@ -0,0 +1,10 @@ +import { readFileSync, writeFileSync } from 'node:fs'; + +export default function migrateAnchor() { + let content = readFileSync('src/anchor/anchor.tsx', 'utf8'); + if (!content.includes("import { CSSProperties } from 'vue/types/jsx';")) { + content = `import { CSSProperties } from 'vue/types/jsx';\n${content}`; + content = content.replace('{activeLineStyle}', '{activeLineStyle as CSSProperties}'); + writeFileSync('src/anchor/anchor.tsx', content, 'utf8'); + } +} diff --git a/script/migrate/components/auto-complete.mjs b/script/migrate/components/auto-complete.mjs new file mode 100644 index 000000000..6707e3244 --- /dev/null +++ b/script/migrate/components/auto-complete.mjs @@ -0,0 +1,10 @@ +import { readFileSync, writeFileSync } from 'node:fs'; + +export default function migrateAutoComplete() { + const filePath = 'src/auto-complete/auto-complete.tsx'; + let content = readFileSync(filePath, 'utf8'); + if (content.includes('...this.popupProps,')) { + content = content.replace('...this.popupProps,', '...(this.popupProps as PopupProps),'); + writeFileSync(filePath, content, 'utf8'); + } +} diff --git a/script/migrate/components/calendar.mjs b/script/migrate/components/calendar.mjs new file mode 100644 index 000000000..65fb9c9d7 --- /dev/null +++ b/script/migrate/components/calendar.mjs @@ -0,0 +1,11 @@ +import { readFileSync, writeFileSync } from 'node:fs'; + +export default function migrateCalendar() { + const filePath = 'src/calendar/calendar-cell.tsx'; + let content = readFileSync(filePath, 'utf8'); + if (!content.includes("import { CSSProperties } from 'vue/types/jsx';")) { + content = `import { CSSProperties } from 'vue/types/jsx';\n${content}`; + content = content.replace('{cellContentOuterDomStyle}', '{cellContentOuterDomStyle as CSSProperties}'); + writeFileSync(filePath, content, 'utf8'); + } +} diff --git a/script/migrate/components/card.mjs b/script/migrate/components/card.mjs new file mode 100644 index 000000000..7a208e0ec --- /dev/null +++ b/script/migrate/components/card.mjs @@ -0,0 +1,10 @@ +import { readFileSync, writeFileSync } from 'node:fs'; + +export default function migrateCard() { + const filePath = 'src/card/card.tsx'; + let content = readFileSync(filePath, 'utf8'); + if (content.includes('{this.cover}')) { + content = content.replace('{this.cover}', '{this.cover as string}'); + writeFileSync(filePath, content, 'utf8'); + } +} diff --git a/script/migrate/components/dropdown.mjs b/script/migrate/components/dropdown.mjs new file mode 100644 index 000000000..e5366e5be --- /dev/null +++ b/script/migrate/components/dropdown.mjs @@ -0,0 +1,13 @@ +import { readFileSync, writeFileSync } from 'node:fs'; + +export default function migrateDropdown() { + const filePath = 'src/dropdown/dropdown-item.tsx'; + let content = readFileSync(filePath, 'utf8'); + if (content.includes('ref={this.itemRef}')) { + content = content.replace( + 'ref={this.itemRef}', + 'ref="itemRef"', + ); + writeFileSync(filePath, content, 'utf8'); + } +} diff --git a/script/migrate/components/migrateImport.mjs b/script/migrate/components/migrateImport.mjs new file mode 100644 index 000000000..3656b8f73 --- /dev/null +++ b/script/migrate/components/migrateImport.mjs @@ -0,0 +1,34 @@ +import glob from 'glob'; +import { readFileSync, writeFileSync } from 'node:fs'; + +export default function migrateImport() { + glob.sync('src/**/*.{tsx,vue,ts}', { ignore: ['src/_common'] }).forEach((file) => { + let content = readFileSync(file, 'utf8'); + let isChange = false; + if (content.includes('@vue/composition-api')) { + content = content.replaceAll('@vue/composition-api', 'vue'); + isChange = true; + } + if (content.includes("import VueCompositionAPI from 'vue';")) { + content = content.replaceAll("import VueCompositionAPI from 'vue';", '') + .replaceAll(', VueCompositionAPI', ''); + isChange = true; + } + if (content.includes('// vue27:ts-ignore')) { + content = content.replaceAll('// vue27:ts-ignore', '// @ts-ignore'); + isChange = true; + } + if (isChange) { + writeFileSync(file, content, 'utf8'); + } + // console.log(`Processing file: ${file}`); + }); + glob.sync('site/**/*.vue', { ignore: ['node_modules'] }).forEach((file) => { + const content = readFileSync(file, 'utf8'); + if (content.includes('@vue/composition-api')) { + const newContent = content.replaceAll('@vue/composition-api', 'vue'); + writeFileSync(file, newContent, 'utf8'); + } + // console.log(`Processing file: ${file}`); + }); +} diff --git a/script/migrate/components/migrateSingleFile.mjs b/script/migrate/components/migrateSingleFile.mjs new file mode 100644 index 000000000..33b25bc21 --- /dev/null +++ b/script/migrate/components/migrateSingleFile.mjs @@ -0,0 +1,17 @@ +import { execSync } from 'node:child_process'; +import { readFileSync, writeFileSync } from 'node:fs'; + +function migrateSrcIndexTs() { + execSync('git restore src/index.ts'); + let content = readFileSync('src/index.ts', 'utf8'); + content = content.replace("import VueCompositionAPI from '@vue/composition-api';", ''); + + // 替换 VueCompositionAPI 安装代码 + content = content.replace(/\s*if \(Vue\._installedPlugins\.indexOf\(VueCompositionAPI\) === -1\) \{\s*Vue\.use\(VueCompositionAPI\);\s*\}/g, ''); + + writeFileSync('src/index.ts', content, 'utf8'); +} + +export default function migrateSingleFile() { + migrateSrcIndexTs(); +} diff --git a/script/migrate/components/range-input.mjs b/script/migrate/components/range-input.mjs new file mode 100644 index 000000000..7e68bdfd1 --- /dev/null +++ b/script/migrate/components/range-input.mjs @@ -0,0 +1,11 @@ +import { readFileSync, writeFileSync } from 'node:fs'; + +export default function migrateRangeInput() { + const filePath = 'src/range-input/range-input.tsx'; + let content = readFileSync(filePath, 'utf8'); + if (content.includes('const instance = getCurrentInstance();')) { + content = content.replace('const instance = getCurrentInstance();', 'const instance = getCurrentInstance().proxy;'); + content = content.replaceAll('instance.emit', 'instance.$emit'); + writeFileSync(filePath, content, 'utf8'); + } +} diff --git a/script/migrate/components/select-input.mjs b/script/migrate/components/select-input.mjs new file mode 100644 index 000000000..b61bb7792 --- /dev/null +++ b/script/migrate/components/select-input.mjs @@ -0,0 +1,34 @@ +import { readFileSync, writeFileSync } from 'node:fs'; + +function migrateUseSingle() { + const filePath = 'src/select-input/useSingle.tsx'; + let content = readFileSync(filePath, 'utf8'); + if (content.includes('const instance = getCurrentInstance();')) { + content = content.replace('const instance = getCurrentInstance();', 'const instance = getCurrentInstance().proxy;'); + content = content.replaceAll('instance.emit', 'instance.$emit'); + writeFileSync(filePath, content, 'utf8'); + } +} +function migrateUseOverlayInnerStyle() { + const filePath = 'src/select-input/useOverlayInnerStyle.ts'; + let content = readFileSync(filePath, 'utf8'); + if (content.includes('const instance = getCurrentInstance();')) { + content = content.replace('const instance = getCurrentInstance();', 'const instance = getCurrentInstance().proxy;'); + content = content.replaceAll('instance.emit', 'instance.$emit'); + writeFileSync(filePath, content, 'utf8'); + } +} +function migrateSelectInput() { + const filePath = 'src/select-input/select-input.tsx'; + let content = readFileSync(filePath, 'utf8'); + if (content.includes('setup(props: TdSelectInputProps')) { + content = content.replace('setup(props: TdSelectInputProps', 'setup(props'); + writeFileSync(filePath, content, 'utf8'); + } +} + +export default function () { + migrateSelectInput(); + migrateUseSingle(); + migrateUseOverlayInnerStyle(); +} diff --git a/script/migrate/components/select.mjs b/script/migrate/components/select.mjs new file mode 100644 index 000000000..e373d700b --- /dev/null +++ b/script/migrate/components/select.mjs @@ -0,0 +1,11 @@ +import { readFileSync, writeFileSync } from 'node:fs'; + +export default function migrateSelect() { + const filePath = 'src/select/select.tsx'; + let content = readFileSync(filePath, 'utf8'); + if (content.includes('const instance = getCurrentInstance();')) { + content = content.replace('const instance = getCurrentInstance();', 'const instance = getCurrentInstance().proxy;'); + content = content.replaceAll('instance.emit', 'instance.$emit'); + writeFileSync(filePath, content, 'utf8'); + } +} diff --git a/script/migrate/components/table.mjs b/script/migrate/components/table.mjs new file mode 100644 index 000000000..c0044cdb4 --- /dev/null +++ b/script/migrate/components/table.mjs @@ -0,0 +1,60 @@ +import { readFileSync, writeFileSync } from 'node:fs'; + +function migrateThead() { + const filePath = 'src/table/thead.tsx'; + let content = readFileSync(filePath, 'utf8'); + if (content.includes('setup(props: TheadProps')) { + content = content.replace('setup(props: TheadProps', 'setup(props'); + writeFileSync(filePath, content, 'utf8'); + } +} +function migrateTbody() { + const filePath = 'src/table/tbody.tsx'; + let content = readFileSync(filePath, 'utf8'); + if (content.includes('setup(props: TableBodyProps')) { + content = content.replace('setup(props: TableBodyProps', 'setup(props'); + writeFileSync(filePath, content, 'utf8'); + } +} +function migrateTfoot() { + const filePath = 'src/table/tfoot.tsx'; + let content = readFileSync(filePath, 'utf8'); + if (content.includes('setup(props: TFootProps')) { + content = content.replace('setup(props: TFootProps', 'setup(props'); + writeFileSync(filePath, content, 'utf8'); + } +} +function migrateTr() { + const filePath = 'src/table/tr.tsx'; + let content = readFileSync(filePath, 'utf8'); + if (content.includes('setup(props: TrProps')) { + content = content.replace('setup(props: TrProps', 'setup(props'); + writeFileSync(filePath, content, 'utf8'); + } +} +function migrateFilterController() { + const filePath = 'src/table/filter-controller.tsx'; + let content = readFileSync(filePath, 'utf8'); + if (content.includes('setup(props: TableFilterControllerProps')) { + content = content.replace('setup(props: TableFilterControllerProps', 'setup(props'); + writeFileSync(filePath, content, 'utf8'); + } +} +function migrateEditableCell() { + const filePath = 'src/table/editable-cell.tsx'; + let content = readFileSync(filePath, 'utf8'); + if (content.includes('this.col.edit')) { + content = content.replace('render() {', 'render() {\nconst col = this.col as PrimaryTableCol;'); + content = content.replaceAll('this.col.edit', 'col.edit'); + writeFileSync(filePath, content, 'utf8'); + } +} + +export default function migrateTable() { + migrateThead(); + migrateTbody(); + migrateTfoot(); + migrateTr(); + migrateFilterController(); + migrateEditableCell(); +} diff --git a/script/migrate/components/timeline.mjs b/script/migrate/components/timeline.mjs new file mode 100644 index 000000000..ba404dd1f --- /dev/null +++ b/script/migrate/components/timeline.mjs @@ -0,0 +1,26 @@ +import { readFileSync, writeFileSync } from 'node:fs'; + +function migrateTimeline() { + const filePath = 'src/timeline/timeline.tsx'; + let content = readFileSync(filePath, 'utf8'); + if (content.includes('const instance = getCurrentInstance();')) { + content = content.replace('const instance = getCurrentInstance();', 'const instance = getCurrentInstance().proxy;'); + content = content.replaceAll('instance.slots', 'instance.$slots'); + writeFileSync(filePath, content, 'utf8'); + } +} + +function migrateTimelineItem() { + const filePath = 'src/timeline/timeline-item.tsx'; + let content = readFileSync(filePath, 'utf8'); + if (content.includes('const instance = getCurrentInstance();')) { + content = content.replace('const instance = getCurrentInstance();', 'const instance = getCurrentInstance().proxy;'); + content = content.replaceAll('instance.parent.slots', 'instance.$parent.$slots'); + writeFileSync(filePath, content, 'utf8'); + } +} + +export default function () { + migrateTimeline(); + migrateTimelineItem(); +} diff --git a/script/migrate/components/tree-select.mjs b/script/migrate/components/tree-select.mjs new file mode 100644 index 000000000..1b600acff --- /dev/null +++ b/script/migrate/components/tree-select.mjs @@ -0,0 +1,12 @@ +import { readFileSync, writeFileSync } from 'node:fs'; + +export default function migrateTreeSelect() { + let content = readFileSync('src/tree-select/tree-select.tsx', 'utf8'); + if (content.includes('...this.treeProps')) { + content = content.replace('...this.treeProps', '...(this.treeProps as TreeProps)').replace("import Tree from '../tree';", "import Tree, { TreeProps } from '../tree';"); + } + if (content.includes('...this.selectInputProps')) { + content = content.replace('...this.selectInputProps', '...(this.selectInputProps as SelectInputProps)').replace("import SelectInput from '../select-input';", "import SelectInput, { SelectInputProps } from '../select-input';"); + } + writeFileSync('src/tree-select/tree-select.tsx', content, 'utf8'); +} diff --git a/script/migrate/components/tree.mjs b/script/migrate/components/tree.mjs new file mode 100644 index 000000000..fca0f2daf --- /dev/null +++ b/script/migrate/components/tree.mjs @@ -0,0 +1,7 @@ +import { readFileSync, writeFileSync } from 'node:fs'; + +export default function migrateTree() { + let content = readFileSync('src/tree/adapt.ts', 'utf8'); + content = content.replace('VueCompositionAPI,', '').replace(', VueCompositionAPI', ''); + writeFileSync('src/tree/adapt.ts', content, 'utf8'); +} diff --git a/script/migrate/components/upload.mjs b/script/migrate/components/upload.mjs new file mode 100644 index 000000000..dae6caba6 --- /dev/null +++ b/script/migrate/components/upload.mjs @@ -0,0 +1,42 @@ +import { readFileSync, writeFileSync } from 'node:fs'; + +function migrateDraggerFile() { + const filePath = 'src/upload/themes/dragger-file.tsx'; + let content = readFileSync(filePath, 'utf8'); + if (content.includes('setup(props: DraggerProps)')) { + content = content.replace('setup(props: DraggerProps)', 'setup(props)'); + writeFileSync(filePath, content, 'utf8'); + } +} +function migrateImageCard() { + const filePath = 'src/upload/themes/image-card.tsx'; + let content = readFileSync(filePath, 'utf8'); + if (content.includes('setup(props: ImageCardUploadProps)')) { + content = content.replace('setup(props: ImageCardUploadProps)', 'setup(props)'); + writeFileSync(filePath, content, 'utf8'); + } +} + +function migrateMultipleFlowList() { + const filePath = 'src/upload/themes/multiple-flow-list.tsx'; + let content = readFileSync(filePath, 'utf8'); + if (content.includes('setup(props: ImageFlowListProps')) { + content = content.replace('setup(props: ImageFlowListProps', 'setup(props'); + writeFileSync(filePath, content, 'utf8'); + } +} + +function migrateNormalFile() { + const filePath = 'src/upload/themes/normal-file.tsx'; + let content = readFileSync(filePath, 'utf8'); + if (content.includes('setup(props: NormalFileProps)')) { + content = content.replace('setup(props: NormalFileProps)', 'setup(props)'); + writeFileSync(filePath, content, 'utf8'); + } +} +export default function migrateUpload() { + migrateDraggerFile(); + migrateImageCard(); + migrateMultipleFlowList(); + migrateNormalFile(); +} diff --git a/script/migrate/components/watermark.mjs b/script/migrate/components/watermark.mjs new file mode 100644 index 000000000..fa468d8fb --- /dev/null +++ b/script/migrate/components/watermark.mjs @@ -0,0 +1,17 @@ +import { readFileSync, writeFileSync } from 'node:fs'; + +function migrateHooks() { + const filePath = 'src/watermark/hooks.ts'; + let content = readFileSync(filePath, 'utf8'); + if (content.includes('export type MaybeElement = HTMLElement | SVGElement')) { + content = content.replace( + 'export type MaybeElement = HTMLElement | SVGElement', + 'export type MaybeElement = Element | HTMLElement | SVGElement', + ).replace('UnRefElementReturn', 'any'); + writeFileSync(filePath, content, 'utf8'); + } +} + +export default function migrateWatermark() { + migrateHooks(); +} diff --git a/script/migrate/config/migrateConfig.mjs b/script/migrate/config/migrateConfig.mjs new file mode 100644 index 000000000..a724ef9b9 --- /dev/null +++ b/script/migrate/config/migrateConfig.mjs @@ -0,0 +1,133 @@ +import { execSync } from 'node:child_process'; +import { readFileSync, writeFileSync } from 'node:fs'; + +export function migratePackageJson() { + execSync('git restore package.json'); + const pkg = JSON.parse(readFileSync('package.json', 'utf8')); + + delete pkg.dependencies['@vue/composition-api']; + delete pkg.devDependencies['vite-plugin-vue2']; + delete pkg.devDependencies['unplugin-vue2-script-setup']; + delete pkg.devDependencies['vue-template-compiler']; + + pkg.peerDependencies = { + ...pkg.peerDependencies, + vue: '~2.7.14', + }; + + pkg.devDependencies = { + ...pkg.devDependencies, + '@vitejs/plugin-vue2': '^2.3.3', + '@vitejs/plugin-vue2-jsx': '^1.1.0', + '@vue/babel-preset-jsx': '^1.3.0', + 'vue-server-renderer': '^2.7.14', + 'vue-demi': '^0.13.1', + 'vue-loader': '^15.10.0', + vue: '~2.7.14', + 'eslint-plugin-vue': '^9.3.0', + '@types/estree': '1.0.0', + csstype: '^3.1.2', + }; + writeFileSync('package.json', `${JSON.stringify(pkg, null, 2)}`, 'utf8'); +} + +export function migrateViteConfig() { + execSync('git restore site/vite.config.js'); + let content = readFileSync('site/vite.config.js', 'utf8'); + content = content + .replace( + "import { createVuePlugin } from 'vite-plugin-vue2';", + `import vue from '@vitejs/plugin-vue2'; +import vueJsx from '@vitejs/plugin-vue2-jsx';`, + ) + .replace('createVuePlugin', 'vue') + .replace("import ScriptSetup from 'unplugin-vue2-script-setup/vite';", '') + .replace('ScriptSetup({}),', '') + .replace('jsx: true,', '') + .replace( + 'tdocPlugin(),', + `vueJsx({}), + tdocPlugin(),`, + ); + writeFileSync('site/vite.config.js', content, 'utf8'); +} + +export function migrateVitestConfig() { + execSync('git restore vitest.config.js'); + let content = readFileSync('vitest.config.js', 'utf8'); + content = content + .replace( + "import { createVuePlugin } from 'vite-plugin-vue2';", + `import vue from '@vitejs/plugin-vue2'; +import vueJsx from '@vitejs/plugin-vue2-jsx';`, + ) + .replace('createVuePlugin', 'vue') + .replace('jsx: true,', '') + .replace("import ScriptSetup from 'unplugin-vue2-script-setup/vite';", '') + .replace('ScriptSetup({}),', '') + .replace( + 'tdocPlugin(),', + `vueJsx({}), + tdocPlugin(),`, + ); + writeFileSync('vitest.config.js', content, 'utf8'); +} + +export function migrateJsxDts() { + const content = `import { PluginObject } from 'vue'; // eslint-disable-line +declare module 'vue' { + interface ComponentInternalInstance { + // todo + [x: string]: any; + } + + interface ComponentCustomProps { + [key: string]: any; + } +} + +declare module 'vue' { + interface VueConstructor { + _installedPlugins: PluginObject[]; + } +} +`; + writeFileSync('jsx.d.ts', content, 'utf8'); +} + +export function migrateTsconfig() { + execSync('git restore tsconfig.json'); + let content = readFileSync('tsconfig.json', 'utf8'); + content = content.replace('"compileOnSave": false', `"compileOnSave": false, + "vueCompilerOptions": { + "target": 2.7 + }`); + + writeFileSync('tsconfig.json', content, 'utf8'); +} +export function migrateBabelConfig() { + execSync('git restore babel.config.js'); + let content = readFileSync('babel.config.js', 'utf8'); + content = content.replaceAll( + "'@vue/babel-preset-jsx',", + `[ + '@vue/babel-preset-jsx', + { + compositionAPI: true, + }, + ],`, + ); + writeFileSync('babel.config.js', content, 'utf8'); +} + +export function migrateCssDTs() { + const content = `import type * as CSS from 'csstype'; + +declare module 'csstype' { + interface Properties { + // Add a missing property + '-moz-transform'?: Property.Transform | undefined; + } +}`; + writeFileSync('css.d.ts', content, 'utf8'); +} diff --git a/script/migrate/hooks/index.mjs b/script/migrate/hooks/index.mjs new file mode 100644 index 000000000..b7d822557 --- /dev/null +++ b/script/migrate/hooks/index.mjs @@ -0,0 +1,11 @@ +import migrateTNode from './tnode.mjs'; +import migrateUseDefaultValue from './useDefaultValue.mjs'; +import migrateUseFormDisabled from './useFormDisabled.mjs'; +import migrateUseVModel from './useVModel.mjs'; + +export default function migrateHooks() { + migrateTNode(); + migrateUseDefaultValue(); + migrateUseFormDisabled(); + migrateUseVModel(); +} diff --git a/script/migrate/hooks/tnode.mjs b/script/migrate/hooks/tnode.mjs new file mode 100644 index 000000000..f540dfe86 --- /dev/null +++ b/script/migrate/hooks/tnode.mjs @@ -0,0 +1,12 @@ +import { readFileSync, writeFileSync } from 'node:fs'; + +export default function migrateTNode() { + const filePath = 'src/hooks/tnode.ts'; + let content = readFileSync(filePath, 'utf-8'); + if (!content.includes('getCurrentInstance().proxy')) { + content = content.replace('getCurrentInstance()', 'getCurrentInstance().proxy') + .replace('const { slots } = instance.setupContext;', 'const slots = instance.$scopedSlots;') + .replaceAll('instance.props', 'instance.$props'); + writeFileSync(filePath, content, 'utf-8'); + } +} diff --git a/script/migrate/hooks/useDefaultValue.mjs b/script/migrate/hooks/useDefaultValue.mjs new file mode 100644 index 000000000..ee6b686a0 --- /dev/null +++ b/script/migrate/hooks/useDefaultValue.mjs @@ -0,0 +1,15 @@ +import { readFileSync, writeFileSync } from 'node:fs'; + +export default function migrateUseDefaultValue() { + const filePath = 'src/hooks/useDefaultValue.ts'; + let content = readFileSync(filePath, 'utf-8'); + if (content.includes('const { emit, vnode } = getCurrentInstance();')) { + content = content.replace( + 'const { emit, vnode } = getCurrentInstance();', + `const instance = getCurrentInstance().proxy; + const emit = instance.$emit; + const vnode = instance.$vnode;`, + ); + writeFileSync(filePath, content, 'utf-8'); + } +} diff --git a/script/migrate/hooks/useFormDisabled.mjs b/script/migrate/hooks/useFormDisabled.mjs new file mode 100644 index 000000000..4446811ed --- /dev/null +++ b/script/migrate/hooks/useFormDisabled.mjs @@ -0,0 +1,15 @@ +import { readFileSync, writeFileSync } from 'node:fs'; + +export default function migrateUseFormDisabled() { + const filePath = 'src/hooks/useFormDisabled.ts'; + let content = readFileSync(filePath, 'utf-8'); + if (content.includes('const currentInstance = getCurrentInstance();')) { + content = content.replace( + 'getCurrentInstance()', + 'getCurrentInstance().proxy', + ).replaceAll('parent', '$parent').replace('$parent.proxy', '$parent') + .replace('parent.props', 'parent.$props'); + content = content.replaceAll('instance.props', 'instance.$props'); + writeFileSync(filePath, content, 'utf-8'); + } +} diff --git a/script/migrate/hooks/useVModel.mjs b/script/migrate/hooks/useVModel.mjs new file mode 100644 index 000000000..7178f385d --- /dev/null +++ b/script/migrate/hooks/useVModel.mjs @@ -0,0 +1,15 @@ +import { readFileSync, writeFileSync } from 'node:fs'; + +export default function migrateUseVModel() { + const filePath = 'src/hooks/useVModel.ts'; + let content = readFileSync(filePath, 'utf-8'); + if (content.includes('const { emit, vnode } = getCurrentInstance();')) { + content = content.replace( + 'const { emit, vnode } = getCurrentInstance();', + `const instance = getCurrentInstance().proxy; + const emit = instance.$emit; + const vnode = instance.$vnode;`, + ); + writeFileSync(filePath, content, 'utf-8'); + } +} diff --git a/script/migrate/migrateComponent.mjs b/script/migrate/migrateComponent.mjs new file mode 100644 index 000000000..4484d452d --- /dev/null +++ b/script/migrate/migrateComponent.mjs @@ -0,0 +1,45 @@ +import migrateImport from './components/migrateImport.mjs'; +import migrateSingleFile from './components/migrateSingleFile.mjs'; +import migrateAnchor from './components/anchor.mjs'; +import migrateAutoComplete from './components/auto-complete.mjs'; +import migrateCalendar from './components/calendar.mjs'; +import migrateCard from './components/card.mjs'; +import migrateDropdown from './components/dropdown.mjs'; +import migrateTree from './components/tree.mjs'; +import migrateTreeSelect from './components/tree-select.mjs'; +import migrateHelper from './utils/helper.mjs'; +import migrateRenderTNode from './utils/render-tnode.mjs'; +import migrateHooks from './hooks/index.mjs'; +import migrateUpload from './components/upload.mjs'; +import migrateTable from './components/table.mjs'; +import migrateTimeline from './components/timeline.mjs'; +import migrateSelect from './components/select.mjs'; +import migrateRangeInput from './components/range-input.mjs'; +import migrateSelectInput from './components/select-input.mjs'; +import migrateWatermark from './components/watermark.mjs'; + +function run() { + migrateSingleFile(); + migrateImport(); + migrateAnchor(); + migrateAutoComplete(); + migrateCalendar(); + migrateDropdown(); + migrateCard(); + migrateUpload(); + migrateSelect(); + migrateSelectInput(); + migrateTable(); + migrateTimeline(); + migrateTree(); + migrateTreeSelect(); + migrateRangeInput(); + migrateWatermark(); + + migrateHelper(); + migrateRenderTNode(); + + migrateHooks(); +} + +run(); diff --git a/script/migrate/migrateConfig.mjs b/script/migrate/migrateConfig.mjs new file mode 100644 index 000000000..2cdcd5ce1 --- /dev/null +++ b/script/migrate/migrateConfig.mjs @@ -0,0 +1,18 @@ +import { + migratePackageJson, migrateViteConfig, migrateVitestConfig, migrateTsconfig, migrateJsxDts, migrateBabelConfig, + migrateCssDTs, +} from './config/migrateConfig.mjs'; + +function run() { + migratePackageJson(); + + migrateViteConfig(); + migrateVitestConfig(); + migrateTsconfig(); + + migrateJsxDts(); + migrateCssDTs(); + migrateBabelConfig(); +} + +run(); diff --git a/script/migrate/utils/helper.mjs b/script/migrate/utils/helper.mjs new file mode 100644 index 000000000..e3d5a6bc6 --- /dev/null +++ b/script/migrate/utils/helper.mjs @@ -0,0 +1,13 @@ +import { readFileSync, writeFileSync } from 'node:fs'; + +export default function migrateHelper() { + let content = readFileSync('src/utils/helper.ts', 'utf8'); + if (!content.includes("import { CSSProperties } from 'vue/types/jsx';")) { + content = `import { CSSProperties } from 'vue/types/jsx';\n${content}`; + content = content.replace( + 'export function setTransform(value: string): object', + 'export function setTransform(value: string): CSSProperties', + ); + writeFileSync('src/utils/helper.ts', content, 'utf8'); + } +} diff --git a/script/migrate/utils/render-tnode.mjs b/script/migrate/utils/render-tnode.mjs new file mode 100644 index 000000000..d1598080b --- /dev/null +++ b/script/migrate/utils/render-tnode.mjs @@ -0,0 +1,12 @@ +import { readFileSync, writeFileSync } from 'node:fs'; + +export default function migrateRenderTNode() { + let content = readFileSync('src/utils/render-tnode.ts', 'utf8'); + if (content.includes('ComponentRenderProxy')) { + content = content.replaceAll( + 'ComponentRenderProxy', + 'CreateComponentPublicInstance', + ); + writeFileSync('src/utils/render-tnode.ts', content, 'utf8'); + } +} diff --git a/src/cascader/cascader.tsx b/src/cascader/cascader.tsx index c033efa91..ab10ed6ef 100644 --- a/src/cascader/cascader.tsx +++ b/src/cascader/cascader.tsx @@ -158,6 +158,7 @@ export default defineComponent({ label: this.label, valueDisplay: renderValueDisplay, suffix: this.suffix, + // vue27:ts-ignore tag: this.tag, readonly: this.readonly, disabled: isDisabled, diff --git a/src/checkbox/checkbox.tsx b/src/checkbox/checkbox.tsx index 9b4343330..4f65d20de 100644 --- a/src/checkbox/checkbox.tsx +++ b/src/checkbox/checkbox.tsx @@ -252,6 +252,7 @@ export default defineComponent({ name={this.tName || this.name || undefined} value={this.value ? this.value : undefined} checked={this.tChecked} + // vue27:ts-ignore on={{ change: this.handleChange }} key="input" tabindex="-1" diff --git a/src/checkbox/group.tsx b/src/checkbox/group.tsx index 00d6d2301..7eb3d02d6 100644 --- a/src/checkbox/group.tsx +++ b/src/checkbox/group.tsx @@ -220,6 +220,7 @@ export default defineComponent({ if (this.options?.length) { children = this.optionList?.map((option, index) => ( )} @@ -106,6 +107,7 @@ export default defineComponent({ style={this.imgStyle} alt="image" draggable="false" + // vue27:ts-ignore referrerpolicy={this.imageReferrerpolicy} /> )} diff --git a/src/image-viewer/base/ImageViewerModal.tsx b/src/image-viewer/base/ImageViewerModal.tsx index 36f803af8..c10550a87 100644 --- a/src/image-viewer/base/ImageViewerModal.tsx +++ b/src/image-viewer/base/ImageViewerModal.tsx @@ -99,6 +99,7 @@ export default defineComponent({ mirror={this.mirror} src={this.currentImage.mainImage} placementSrc={this.currentImage.thumbnail} + // vue27:ts-ignore imageReferrerpolicy={props.imageReferrerpolicy} /> diff --git a/src/image/image.tsx b/src/image/image.tsx index 8071278ca..fb5e2d8cc 100644 --- a/src/image/image.tsx +++ b/src/image/image.tsx @@ -181,6 +181,7 @@ export default defineComponent({ onLoad={this.handleLoad} class={this.imageClasses} alt={this.alt} + // vue27:ts-ignore referrerpolicy={this.referrerpolicy} /> ); @@ -200,6 +201,7 @@ export default defineComponent({ onMouseenter={this.handleToggleOverlay} onMouseleave={this.handleToggleOverlay} {...this.rest} + // vue27:ts-ignore on={this.$listeners} > {this.renderPlaceholder()} diff --git a/src/input/input.tsx b/src/input/input.tsx index 8baa443d6..359a3e457 100644 --- a/src/input/input.tsx +++ b/src/input/input.tsx @@ -582,6 +582,7 @@ export default mixins( {labelContent} {/* input element must exist, or other select components can not focus by keyboard operation */} , classPre tabindex="-1" data-value={typeof this.value === 'string' ? `'${this.value}'` : this.value} data-allow-uncheck={allowUncheck || undefined} + // vue27:ts-ignore on={{ ...omit(this.$listeners, ['change', 'click']) }} /> diff --git a/src/select-input/select-input.tsx b/src/select-input/select-input.tsx index d43439858..bac0e155b 100644 --- a/src/select-input/select-input.tsx +++ b/src/select-input/select-input.tsx @@ -117,6 +117,7 @@ export default defineComponent({ const mainContent = ( diff --git a/src/table/base-table.tsx b/src/table/base-table.tsx index b1a4c380a..2266b4736 100644 --- a/src/table/base-table.tsx +++ b/src/table/base-table.tsx @@ -626,6 +626,7 @@ export default defineComponent({ key="table-content" class={this.tableBaseClass.content} style={this.tableContentStyles} + // vue27:ts-ignore on={{ scroll: this.onInnerVirtualScroll }} > {this.virtualConfig.isVirtualScroll.value && ( diff --git a/src/table/filter-controller.tsx b/src/table/filter-controller.tsx index 4482d6639..2442fe2b8 100644 --- a/src/table/filter-controller.tsx +++ b/src/table/filter-controller.tsx @@ -127,7 +127,9 @@ export default defineComponent({ options: ['single', 'multiple'].includes(column.filter.type) ? this.getFilterDisplayList(column) : undefined, ...(column.filter?.props || {}), }; + // vue27:ts-ignore if (column.colKey && this.innerFilterValue && column.colKey in this.innerFilterValue) { + // vue27:ts-ignore filterComponentProps.value = this.innerFilterValue[column.colKey]; } // 这个代码必须放在这里,否则会造成顺序错误 @@ -169,6 +171,7 @@ export default defineComponent({ }); }); } + // vue27:ts-ignore const filter = this.column.filter || {}; return ( {column.filter.listFilterConfig && ( ; + // vue27:ts-ignore const filterValue = this.tFilterValue?.[column.colKey]; const isObjectTrue = typeof filterValue === 'object' && !isEmpty(filterValue); // false is a valid filter value diff --git a/src/table/primary-table.tsx b/src/table/primary-table.tsx index 340ee403d..99b6e853b 100644 --- a/src/table/primary-table.tsx +++ b/src/table/primary-table.tsx @@ -428,6 +428,7 @@ export default defineComponent({ render() { const isColumnController = !!(this.columnController && Object.keys(this.columnController).length); + // vue27:ts-ignore const placement = isColumnController ? this.columnController.placement || 'top-right' : ''; const isBottomController = isColumnController && placement?.indexOf('bottom') !== -1; const topContent = this.formatNode( diff --git a/src/table/tbody.tsx b/src/table/tbody.tsx index 8ea26c48f..531c6f02f 100644 --- a/src/table/tbody.tsx +++ b/src/table/tbody.tsx @@ -164,7 +164,9 @@ export default defineComponent({
{fullRowNode}
diff --git a/src/table/tfoot.tsx b/src/table/tfoot.tsx index 80caada77..5d81610dc 100644 --- a/src/table/tfoot.tsx +++ b/src/table/tfoot.tsx @@ -85,6 +85,7 @@ export default defineComponent({ this.rowKey || 'id', ); return ( + // vue27:ts-ignore {this.columns.map((col, colIndex) => { const cellSpans: RowspanColspan = {}; @@ -107,6 +108,7 @@ export default defineComponent({ style.width = `${this.thWidthList[col.colKey]}px`; } return ( + // vue27:ts-ignore {this.renderTFootCell({ row, diff --git a/src/table/thead.tsx b/src/table/thead.tsx index 8acc8a67f..0217e8381 100644 --- a/src/table/thead.tsx +++ b/src/table/thead.tsx @@ -203,7 +203,9 @@ export default defineComponent({ data-colkey={col.colKey} class={thClasses} style={styles} + // vue27:ts-ignore attrs={{ ...attrs, ...rowspanAndColspan }} + // vue27:ts-ignore on={resizeColumnListener} >
diff --git a/src/table/tr.tsx b/src/table/tr.tsx index 408571d35..26a81dc59 100644 --- a/src/table/tr.tsx +++ b/src/table/tr.tsx @@ -277,6 +277,7 @@ export default defineComponent({ return ( this.tableElm : undefined)} tooltipContent={content && (() => content)} tooltipProps={tooltipProps} @@ -321,6 +322,7 @@ export default defineComponent({ const normalAttrs = isFunction(col.attrs) ? col.attrs({ ...params, type: 'td' }) : col.attrs; const attrs: { [key: string]: any } = { ...normalAttrs, ...cellSpans }; return ( + // vue27:ts-ignore {col.ellipsis ? this.renderEllipsisCell(h, params, { cellNode }) : cellNode} @@ -360,6 +362,7 @@ export default defineComponent({ return ( { let index = 0; uidArr.value.forEach((item: number | undefined, itemIndex: number) => { + // vue27:ts-ignore if (item === instance.uid) { index = itemIndex; } @@ -111,6 +112,7 @@ export default defineComponent({ const { dotColor, dotClassName, + // vue27:ts-ignore style = {}, labelClassName, mode, diff --git a/src/timeline/timeline.tsx b/src/timeline/timeline.tsx index a100e763a..1c099290f 100644 --- a/src/timeline/timeline.tsx +++ b/src/timeline/timeline.tsx @@ -65,6 +65,7 @@ export default defineComponent({ if (reverse) { defaultSlot.reverse(); } + // vue27:ts-ignore const { timelineClassName, style } = this; return (
    diff --git a/src/tree-select/tree-select.tsx b/src/tree-select/tree-select.tsx index 65fee5765..3b2f3dc18 100644 --- a/src/tree-select/tree-select.tsx +++ b/src/tree-select/tree-select.tsx @@ -98,7 +98,9 @@ export default defineComponent({ filter: this.filterByText, icon: !this.filterByText, activeMultiple: this.multiple, + // vue27:ts-ignore onExpand: this.treeNodeExpand, + // vue27:ts-ignore onLoad: this.treeNodeLoad, onChange: this.treeNodeChange, onActive: this.treeNodeActive, diff --git a/src/tree/hooks/useRenderIcon.tsx b/src/tree/hooks/useRenderIcon.tsx index 427d32c98..7bb15cbcd 100644 --- a/src/tree/hooks/useRenderIcon.tsx +++ b/src/tree/hooks/useRenderIcon.tsx @@ -58,7 +58,9 @@ export default function useRenderIcon(state: TypeTreeItemState) { `${classPrefix}-folder-icon`, isDefaultIcon ? `${componentName}__icon--default` : '', ]} + // vue27:ts-ignore trigger="expand" + // vue27:ts-ignore ignore="active" onmousedown={handleMousedown} > diff --git a/src/tree/hooks/useRenderOperations.tsx b/src/tree/hooks/useRenderOperations.tsx index b977b4eb7..fcf64b9e5 100644 --- a/src/tree/hooks/useRenderOperations.tsx +++ b/src/tree/hooks/useRenderOperations.tsx @@ -25,6 +25,7 @@ export default function useRenderOperations(state: TypeTreeItemState) { } if (opNode) { opNode = ( + // vue27:ts-ignore {opNode} diff --git a/src/upload/themes/multiple-flow-list.tsx b/src/upload/themes/multiple-flow-list.tsx index cbbd60610..6a6ea546a 100644 --- a/src/upload/themes/multiple-flow-list.tsx +++ b/src/upload/themes/multiple-flow-list.tsx @@ -314,6 +314,7 @@ export default defineComponent({ if (list) return list; return ( + // vue27:ts-ignore @@ -457,6 +458,7 @@ export default defineComponent({ {this.theme === 'image-flow' && ( + // vue27:ts-ignore
    {this.displayFiles.length ? this.renderImageList() : this.renderEmpty()}
    @@ -466,6 +468,7 @@ export default defineComponent({ && (this.displayFiles.length ? ( this.renderFileList() ) : ( + // vue27:ts-ignore
    {this.renderEmpty()}
    diff --git a/src/upload/upload.tsx b/src/upload/upload.tsx index c86ea72d2..6ae177507 100644 --- a/src/upload/upload.tsx +++ b/src/upload/upload.tsx @@ -264,6 +264,7 @@ export default defineComponent({ multiple={this.multiple} accept={this.accept} hidden + // vue27:ts-ignore attrs={this.inputAttributes} /> {['file', 'file-input'].includes(this.theme) && !this.draggable && this.getNormalFileNode()}