diff --git a/.eslintignore b/.eslintignore index 9442ad986c501..8a0079a68e696 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,3 +1,4 @@ node_modules +dist packages/*/es packages/*/lib diff --git a/.eslintrc.js b/.eslintrc.js index 64d5e731e2ff0..3888eeb20935d 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -12,8 +12,12 @@ module.exports = { browser: true, node: true, }, - plugins: ['@typescript-eslint', 'prettier'], + globals: { + jest: 'readonly', + }, + plugins: ['@typescript-eslint', 'prettier', 'import'], extends: [ + 'eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:vue/vue3-recommended', 'prettier', @@ -26,7 +30,6 @@ module.exports = { }, }, { - // not tested files: ['**/__tests__/**'], rules: { 'no-console': 'off', @@ -44,6 +47,9 @@ module.exports = { camelcase: ['error', { properties: 'never' }], 'no-var': 'error', + 'no-empty': ['error', { allowEmptyCatch: true }], + 'no-with': 'error', + 'no-void': 'error', 'prefer-const': [ 'warn', { destructuring: 'all', ignoreReadBeforeAssign: true }, @@ -55,20 +61,59 @@ module.exports = { { ignoreConstructors: false, avoidQuotes: true }, ], 'block-scoped-var': 'error', - complexity: ['off', 11], - 'no-with': 'error', - 'no-void': 'error', + 'no-constant-condition': ['error', { checkLoops: false }], '@typescript-eslint/explicit-module-boundary-types': 'off', '@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-non-null-assertion': 'off', '@typescript-eslint/no-non-null-asserted-optional-chain': 'off', + '@typescript-eslint/consistent-type-imports': [ + 'error', + { disallowTypeAnnotations: false }, + ], // vue 'vue/no-v-html': 'off', 'vue/require-default-prop': 'off', 'vue/require-explicit-emits': 'off', - 'prettier/prettier': 'warn', + 'prettier/prettier': 'error', + + // import + 'import/first': 'error', + 'import/no-duplicates': 'error', + 'import/order': [ + 'error', + { + groups: [ + 'builtin', + 'external', + 'internal', + 'parent', + 'sibling', + 'index', + 'object', + 'type', + ], + + pathGroups: [ + { + pattern: 'vue', + group: 'external', + position: 'before', + }, + { + pattern: '@vue/**', + group: 'external', + position: 'before', + }, + { + pattern: '@element-plus/**', + group: 'internal', + }, + ], + pathGroupsExcludedImportTypes: ['type'], + }, + ], }, } diff --git a/build/build-helper.ts b/build/build-helper.ts index 0bb26f5527cba..615d67a1ccd7c 100644 --- a/build/build-helper.ts +++ b/build/build-helper.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-var-requires */ -import helper from 'components-helper' import path from 'path' +import helper from 'components-helper' import { epRoot } from './paths' const { name, version } = require(path.resolve(epRoot, './package.json')) @@ -30,13 +30,10 @@ helper({ }) function reComponentName(title) { - return ( - 'el-' + - title - .replace(/\B([A-Z])/g, '-$1') - .replace(/[ ]+/g, '-') - .toLowerCase() - ) + return `el-${title + .replace(/\B([A-Z])/g, '-$1') + .replace(/[ ]+/g, '-') + .toLowerCase()}` } function reDocUrl(fileName, header) { @@ -44,10 +41,10 @@ function reDocUrl(fileName, header) { const _header = header ? header.replace(/[ ]+/g, '-').toLowerCase() : undefined - return docs + fileName + (_header ? '#' + _header : '') + return docs + fileName + (_header ? `#${_header}` : '') } -function reAttribute(value, key, item) { +function reAttribute(value, key /* , item */) { const _value = value.match(/^\*\*(.*)\*\*$/) const str = _value ? _value[1] : value diff --git a/build/build-indices.ts b/build/build-indices.ts index e3391f6dc0e6e..2a48ba5039106 100644 --- a/build/build-indices.ts +++ b/build/build-indices.ts @@ -1,66 +1,65 @@ -/* eslint-disable @typescript-eslint/no-var-requires */ -'use strict' +// TODO: implement this feature -import fs from 'fs' -import algoliasearch from 'algoliasearch' -import fg from 'fast-glob' +// import fs from 'fs' +// import algoliasearch from 'algoliasearch' +// import fg from 'fast-glob' -interface Index { - component: string - title: string - anchor: string - content: string - sort: number - path: string -} +// interface Index { +// component: string +// title: string +// anchor: string +// content: string +// sort: number +// path: string +// } -const algoliaKey = process.env.ALGOLIA_KEY! +// const algoliaKey = process.env.ALGOLIA_KEY! -const client = algoliasearch('7DCTSU0WBW', algoliaKey) -const langs = { - 'zh-CN': 'element-zh', - 'en-US': 'element-en', - es: 'element-es', - 'fr-FR': 'element-fr', - jp: 'element-jp', -} -;['zh-CN', 'en-US', 'es', 'fr-FR', 'jp'].forEach((lang) => { - const indexName = langs[lang] - const index = client.initIndex(indexName) - index - .clearObjects() - .then(() => { - const files = fg.sync(`website/docs/${lang}/*.md`) - let indices: Index[] = [] - files.forEach((file) => { - const regExp = new RegExp(`website\/docs\/${lang}\/(.*).md`) - const pathContent = file.match(regExp)! - const path = pathContent[1] - const index = path.lastIndexOf('/') - const names = index !== -1 ? path.split('/') : [] - const component = names.length ? names[names.length - 1] : path - const content = fs.readFileSync(file, 'utf8') - const matches = content - .replace(/:::[\s\S]*?:::/g, '') - .replace(/```[\s\S]*?```/g, '') - .match(/#{2,4}[^#]*/g)! - .map((match) => - match - .replace(/\n+/g, '\n') - .split('\n') - .filter((part) => !!part) - ) - }) +// const client = algoliasearch('7DCTSU0WBW', algoliaKey) +// const langs = { +// 'zh-CN': 'element-zh', +// 'en-US': 'element-en', +// es: 'element-es', +// 'fr-FR': 'element-fr', +// jp: 'element-jp', +// } +// ;['zh-CN', 'en-US', 'es', 'fr-FR', 'jp'].forEach((lang) => { +// const indexName = langs[lang] +// const index = client.initIndex(indexName) +// index +// .clearObjects() +// .then(() => { +// const files = fg.sync(`website/docs/${lang}/*.md`) +// let indices: Index[] = [] +// files.forEach((file) => { +// const regExp = new RegExp(`website\/docs\/${lang}\/(.*).md`) +// const pathContent = file.match(regExp)! +// const path = pathContent[1] +// const index = path.lastIndexOf('/') +// const names = index !== -1 ? path.split('/') : [] +// const component = names.length ? names[names.length - 1] : path +// const content = fs.readFileSync(file, 'utf8') +// const matches = content +// .replace(/:::[\s\S]*?:::/g, '') +// .replace(/```[\s\S]*?```/g, '') +// .match(/#{2,4}[^#]*/g)! +// .map((match) => +// match +// .replace(/\n+/g, '\n') +// .split('\n') +// .filter((part) => !!part) +// ) +// }) - index - .saveObjects(indices, { - autoGenerateObjectIDIfNotExist: true, - }) - .catch((e) => { - console.log(e) - }) - }) - .catch((e) => { - console.log(e) - }) -}) +// index +// .saveObjects(indices, { +// autoGenerateObjectIDIfNotExist: true, +// }) +// .catch((e) => { +// console.log(e) +// }) +// }) +// .catch((e) => { +// console.log(e) +// }) +// }) diff --git a/build/crowdin-credentials.ts b/build/crowdin-credentials.ts index bb23ef886891c..f6bb3fb0f215d 100644 --- a/build/crowdin-credentials.ts +++ b/build/crowdin-credentials.ts @@ -1,6 +1,7 @@ import path from 'path' import fs from 'fs' import chalk from 'chalk' +import { errorAndExit } from './utils' const credentialPlaceholder = 'API_TOKEN_PLACEHOLDER' @@ -18,7 +19,7 @@ const CREDENTIAL = process.env.CROWDIN_TOKEN file.replace(credentialPlaceholder, CREDENTIAL!) ) console.info(chalk.green('Crowdin credential update successfully')) - } catch (e) { - throw e + } catch (e: any) { + errorAndExit(e) } })() diff --git a/build/full-bundle.ts b/build/full-bundle.ts index 22e3ab47e3562..f45013b6805e3 100644 --- a/build/full-bundle.ts +++ b/build/full-bundle.ts @@ -1,8 +1,8 @@ +import path from 'path' +import fs from 'fs' import { nodeResolve } from '@rollup/plugin-node-resolve' import rollup from 'rollup' import chalk from 'chalk' -import path from 'path' -import fs from 'fs' import commonjs from '@rollup/plugin-commonjs' import vue from 'rollup-plugin-vue' import esbuild from 'rollup-plugin-esbuild' diff --git a/build/gen-dts.ts b/build/gen-dts.ts index e122191bdf443..1c679110cc958 100644 --- a/build/gen-dts.ts +++ b/build/gen-dts.ts @@ -1,9 +1,10 @@ import path from 'path' import fs from 'fs' -import { Project, SourceFile } from 'ts-morph' import vueCompiler from '@vue/compiler-sfc' +import { Project } from 'ts-morph' import { sync as globSync } from 'fast-glob' import chalk from 'chalk' +import type { SourceFile } from 'ts-morph' const TSCONFIG_PATH = path.resolve(__dirname, '../tsconfig.json') @@ -130,9 +131,9 @@ const genVueTypes = async ( ) console.log( chalk.green( - 'Definition for file: ' + - chalk.bold(sourceFile.getBaseName()) + - ' generated' + `Definition for file: ${chalk.bold( + sourceFile.getBaseName() + )} generated` ) ) } diff --git a/build/gen-entry-dts.ts b/build/gen-entry-dts.ts index f2680aa6e54a4..898758a2baae1 100644 --- a/build/gen-entry-dts.ts +++ b/build/gen-entry-dts.ts @@ -2,12 +2,13 @@ import path from 'path' import fs from 'fs' import chalk from 'chalk' import glob from 'fast-glob' -import { Project, SourceFile } from 'ts-morph' +import { Project } from 'ts-morph' import { epRoot, buildOutput } from './paths' +import type { SourceFile } from 'ts-morph' const TSCONFIG_PATH = path.resolve(__dirname, '../tsconfig.dts.json') const gen = async () => { - const files = await glob(epRoot + '/*.ts') + const files = await glob(`${epRoot}/*.ts`) const project = new Project({ compilerOptions: { allowJs: true, @@ -51,9 +52,9 @@ const gen = async () => { ) console.log( chalk.green( - 'Definition for file: ' + - chalk.bold(sourceFile.getBaseName()) + - ' generated' + `Definition for file: ${chalk.bold( + sourceFile.getBaseName() + )} generated` ) ) } diff --git a/build/gulpfile.ts b/build/gulpfile.ts index a56c3438765ae..4b92ec50501ab 100644 --- a/build/gulpfile.ts +++ b/build/gulpfile.ts @@ -1,6 +1,6 @@ +import path from 'path' import gulp from 'gulp' import ts from 'gulp-typescript' -import path from 'path' import through2 from 'through2' const output = path.resolve(__dirname, '../dist/styles') diff --git a/build/rollup.config.ts b/build/rollup.config.ts index c36085762b658..7d96e6b105aee 100644 --- a/build/rollup.config.ts +++ b/build/rollup.config.ts @@ -1,8 +1,8 @@ +import path from 'path' import vue from 'rollup-plugin-vue' import css from 'rollup-plugin-css-only' import { nodeResolve } from '@rollup/plugin-node-resolve' import esbuild from 'rollup-plugin-esbuild' -import path from 'path' import { getPackagesSync } from '@lerna/project' import pkg from '../package.json' @@ -61,7 +61,7 @@ export default inputs.map((name: string) => ({ return ( /^vue/.test(id) || /^@element-plus/.test(id) || - deps.some((k) => new RegExp('^' + k).test(id)) + deps.some((k) => new RegExp(`^${k}`).test(id)) ) }, })) diff --git a/build/size-reporter.ts b/build/size-reporter.ts index a66c2e10a4072..d0ca168296bf2 100644 --- a/build/size-reporter.ts +++ b/build/size-reporter.ts @@ -1,5 +1,5 @@ import chalk from 'chalk' -import { FileSizeReporter } from 'rollup-plugin-filesize' +import type { FileSizeReporter } from 'rollup-plugin-filesize' const reporter: FileSizeReporter = (opt, outputOptions, info) => { const values = [ diff --git a/build/update-version.ts b/build/update-version.ts index 22d15491fac75..3a818e304d545 100644 --- a/build/update-version.ts +++ b/build/update-version.ts @@ -1,6 +1,6 @@ -import chalk from 'chalk' import path from 'path' import fs from 'fs' +import chalk from 'chalk' import { epRoot } from './paths' const tagVersion = process.env.TAG_VERSION diff --git a/build/utils.ts b/build/utils.ts index 14d851dd492ac..d1d4d01f0b7c9 100644 --- a/build/utils.ts +++ b/build/utils.ts @@ -27,7 +27,7 @@ export const getExternals = (options: { full: boolean }) => (id: string) => { } return [...new Set(packages)].some( - (pkg) => id === pkg || id.startsWith(`${pkg}\/`) + (pkg) => id === pkg || id.startsWith(`${pkg}/`) ) } diff --git a/docs/examples/.eslintrc.js b/docs/examples/.eslintrc.js new file mode 100644 index 0000000000000..d99509b753e00 --- /dev/null +++ b/docs/examples/.eslintrc.js @@ -0,0 +1,7 @@ +module.exports = { + rules: { + 'no-console': 'off', + 'no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': 'off', + }, +} diff --git a/docs/examples/table/summary.vue b/docs/examples/table/summary.vue index abd1f0f47423e..620862fc1deee 100644 --- a/docs/examples/table/summary.vue +++ b/docs/examples/table/summary.vue @@ -77,16 +77,14 @@ export default { } const values = data.map((item) => Number(item[column.property])) if (!values.every((value) => isNaN(value))) { - sums[index] = - '$ ' + - values.reduce((prev, curr) => { - const value = Number(curr) - if (!isNaN(value)) { - return prev + curr - } else { - return prev - } - }, 0) + sums[index] = `$ ${values.reduce((prev, curr) => { + const value = Number(curr) + if (!isNaN(value)) { + return prev + curr + } else { + return prev + } + }, 0)}` } else { sums[index] = 'N/A' } diff --git a/docs/examples/table/with-status.vue b/docs/examples/table/with-status.vue index a87b5925177ec..7eba3a4363488 100644 --- a/docs/examples/table/with-status.vue +++ b/docs/examples/table/with-status.vue @@ -10,15 +10,6 @@ - - + + diff --git a/docs/examples/tabs/customized-trigger.vue b/docs/examples/tabs/customized-trigger.vue index 76a6613a4707d..ba18061ff1f44 100644 --- a/docs/examples/tabs/customized-trigger.vue +++ b/docs/examples/tabs/customized-trigger.vue @@ -42,7 +42,7 @@ export default { }, methods: { addTab(targetName) { - const newTabName = ++this.tabIndex + '' + const newTabName = `${++this.tabIndex}` this.editableTabs.push({ title: 'New Tab', name: newTabName, diff --git a/docs/examples/tabs/dynamic-tabs.vue b/docs/examples/tabs/dynamic-tabs.vue index 52800d1e4371c..32e9f0a725464 100644 --- a/docs/examples/tabs/dynamic-tabs.vue +++ b/docs/examples/tabs/dynamic-tabs.vue @@ -38,7 +38,7 @@ export default { methods: { handleTabsEdit(targetName, action) { if (action === 'add') { - const newTabName = ++this.tabIndex + '' + const newTabName = `${++this.tabIndex}` this.editableTabs.push({ title: 'New Tab', name: newTabName, diff --git a/docs/examples/tag/editable.vue b/docs/examples/tag/editable.vue index 38cddb91fe320..bf6add7b663f6 100644 --- a/docs/examples/tag/editable.vue +++ b/docs/examples/tag/editable.vue @@ -23,24 +23,6 @@ > - - + + diff --git a/docs/examples/transfer/basic.vue b/docs/examples/transfer/basic.vue index 46256d929de74..067dd64db3879 100644 --- a/docs/examples/transfer/basic.vue +++ b/docs/examples/transfer/basic.vue @@ -59,13 +59,6 @@ - - + + diff --git a/docs/examples/tree/customized-node.vue b/docs/examples/tree/customized-node.vue index c4a575cd26a51..0819e54401712 100644 --- a/docs/examples/tree/customized-node.vue +++ b/docs/examples/tree/customized-node.vue @@ -3,7 +3,7 @@

Using render-content

Using scoped slot

d.id === data.id) children.splice(index, 1) - this.data = [...this.data] + this.dataSource = [...this.dataSource] }, renderContent(h, { node, data, store }) { diff --git a/docs/examples/tree/selectable.vue b/docs/examples/tree/selectable.vue index 567fa56e04a3f..9ee9a997f57d4 100644 --- a/docs/examples/tree/selectable.vue +++ b/docs/examples/tree/selectable.vue @@ -46,10 +46,10 @@ export default { if (hasChild) { data = [ { - name: 'zone' + this.count++, + name: `zone${this.count++}`, }, { - name: 'zone' + this.count++, + name: `zone${this.count++}`, }, ] } else { diff --git a/docs/examples/upload/avatar.vue b/docs/examples/upload/avatar.vue index 75f542c0751a0..acabd31151493 100644 --- a/docs/examples/upload/avatar.vue +++ b/docs/examples/upload/avatar.vue @@ -11,32 +11,6 @@ - - + + diff --git a/package.json b/package.json index a2c8f60ad1a1e..4d0646f86f79e 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,8 @@ "build:tokens": "cd packages/tokens && yarn clean && yarn build", "build:full-bundle": "esno build/full-bundle.ts", "format": "prettier --write .", - "lint": "eslint ./packages --ext .vue,.js,.ts,.jsx,.tsx && prettier --check .", - "lint:fix": "eslint --fix ./packages --ext .vue,.js,.ts,.jsx,.tsx && prettier --write .", + "lint": "eslint . --ext .vue,.js,.ts,.jsx,.tsx && prettier --check .", + "lint:fix": "eslint --fix . --ext .vue,.js,.ts,.jsx,.tsx && prettier --write .", "prepare": "husky install", "docs:dev": "if [ ! -d \"dist/element-plus\" ]; then sh scripts/build.sh; fi && yarn docs:gen-locale && cd docs && yarn dev", "docs:build": "cd docs && yarn build", @@ -99,6 +99,7 @@ "esbuild": "^0.12.25", "eslint": "^7.7.0", "eslint-config-prettier": "^8.3.0", + "eslint-plugin-import": "^2.24.2", "eslint-plugin-prettier": "^4.0.0", "eslint-plugin-vue": "^7.0.0-beta.0", "esno": "^0.9.1", diff --git a/packages/components/affix/__tests__/affix.spec.ts b/packages/components/affix/__tests__/affix.spec.ts index bb0784f477aa6..4fb0c69c553cb 100644 --- a/packages/components/affix/__tests__/affix.spec.ts +++ b/packages/components/affix/__tests__/affix.spec.ts @@ -1,7 +1,7 @@ +import { nextTick } from 'vue' import { mount } from '@vue/test-utils' import { defineGetter, makeScroll } from '@element-plus/test-utils' import Affix from '../src/affix.vue' -import { nextTick } from 'vue' let clientHeightRestore: () => void diff --git a/packages/components/alert/src/alert.ts b/packages/components/alert/src/alert.ts index 051e44a561d2b..503689114cf28 100644 --- a/packages/components/alert/src/alert.ts +++ b/packages/components/alert/src/alert.ts @@ -1,5 +1,5 @@ -import type { ExtractPropTypes } from 'vue' import { buildProp, keyOf } from '@element-plus/utils/props' +import type { ExtractPropTypes } from 'vue' export type AlertEffect = 'light' | 'dark' diff --git a/packages/components/autocomplete/__tests__/autocomplete.spec.ts b/packages/components/autocomplete/__tests__/autocomplete.spec.ts index 37bc49069e26e..dc31f3fa18816 100644 --- a/packages/components/autocomplete/__tests__/autocomplete.spec.ts +++ b/packages/components/autocomplete/__tests__/autocomplete.spec.ts @@ -1,11 +1,11 @@ import { mount } from '@vue/test-utils' -import { sleep } from '@element-plus/test-utils' import { NOOP } from '@vue/shared' - -jest.unmock('lodash/debounce') +import { sleep } from '@element-plus/test-utils' import Autocomplete from '../src/index.vue' +jest.unmock('lodash/debounce') + const _mount = (payload = {}) => mount({ components: { diff --git a/packages/components/autocomplete/index.ts b/packages/components/autocomplete/index.ts index 1983d79047118..da2cfca19650c 100644 --- a/packages/components/autocomplete/index.ts +++ b/packages/components/autocomplete/index.ts @@ -1,6 +1,6 @@ -import { App } from 'vue' -import type { SFCWithInstall } from '@element-plus/utils/types' import Autocomplete from './src/index.vue' +import type { App } from 'vue' +import type { SFCWithInstall } from '@element-plus/utils/types' Autocomplete.install = (app: App): void => { app.component(Autocomplete.name, Autocomplete) diff --git a/packages/components/autocomplete/src/index.vue b/packages/components/autocomplete/src/index.vue index 380c1dba43e88..1b18dc3ca16be 100644 --- a/packages/components/autocomplete/src/index.vue +++ b/packages/components/autocomplete/src/index.vue @@ -107,7 +107,8 @@ import { UPDATE_MODEL_EVENT } from '@element-plus/utils/constants' import { throwError } from '@element-plus/utils/error' import ElInput from '@element-plus/components/input' import ElScrollbar from '@element-plus/components/scrollbar' -import ElPopper, { Effect, Placement } from '@element-plus/components/popper' +import ElPopper, { Effect } from '@element-plus/components/popper' +import type { Placement } from '@element-plus/components/popper' import type { PropType } from 'vue' diff --git a/packages/components/avatar/index.ts b/packages/components/avatar/index.ts index 9ca8e85c0ebfb..10c479505cdf0 100644 --- a/packages/components/avatar/index.ts +++ b/packages/components/avatar/index.ts @@ -1,5 +1,5 @@ -import Avatar from './src/avatar.vue' import { withInstall } from '@element-plus/utils/with-install' +import Avatar from './src/avatar.vue' export const ElAvatar = withInstall(Avatar) export default ElAvatar diff --git a/packages/components/backtop/index.ts b/packages/components/backtop/index.ts index 18502bc68ad37..2ec05ac1e58f3 100644 --- a/packages/components/backtop/index.ts +++ b/packages/components/backtop/index.ts @@ -1,5 +1,5 @@ -import { App } from 'vue' import Backtop from './src/index.vue' +import type { App } from 'vue' import type { SFCWithInstall } from '@element-plus/utils/types' diff --git a/packages/components/button/src/button.vue b/packages/components/button/src/button.vue index a3d0457e365ca..f388b4a28ba03 100644 --- a/packages/components/button/src/button.vue +++ b/packages/components/button/src/button.vue @@ -24,8 +24,8 @@