diff --git a/.antd-tools.config.js b/.antd-tools.config.js index 04f8e8744d..96d5024be4 100644 --- a/.antd-tools.config.js +++ b/.antd-tools.config.js @@ -19,7 +19,7 @@ function finalizeCompile() { `{ version: '${packageInfo.version}' }`, ), ); - // eslint-disable-next-line + // eslint-disable-next-line no-console console.log('Wrote version into lib/version/index.js'); // Build package.json version to lib/version/index.d.ts @@ -29,7 +29,7 @@ function finalizeCompile() { versionDefPath, `declare var _default: "${packageInfo.version}";\nexport default _default;\n`, ); - // eslint-disable-next-line + // eslint-disable-next-line no-console console.log('Wrote version into lib/version/index.d.ts'); // Build a entry less file to dist/antd.less @@ -57,7 +57,7 @@ function buildThemeFile(theme, vars) { `@import "../lib/style/${theme}.less";\n@import "../lib/style/components.less";`, ); - // eslint-disable-next-line + // eslint-disable-next-line no-console console.log(`Built a entry less file to dist/antd.${theme}.less`); // Build ${theme}.js: dist/${theme}-theme.js, for less-loader @@ -67,7 +67,7 @@ function buildThemeFile(theme, vars) { `module.exports = ${JSON.stringify(vars, null, 2)};`, ); - // eslint-disable-next-line + // eslint-disable-next-line no-console console.log(`Built a ${theme} theme js file to dist/${theme}-theme.js`); } @@ -78,7 +78,7 @@ function finalizeDist() { path.join(process.cwd(), 'dist', 'antd.less'), '@import "../lib/style/index.less";\n@import "../lib/style/components.less";', ); - // eslint-disable-next-line + // eslint-disable-next-line no-console console.log('Built a entry less file to dist/antd.less'); buildThemeFile('dark', darkVars); buildThemeFile('compact', compactVars); diff --git a/.eslintrc.js b/.eslintrc.js index a5e13bf4c2..3147b2293e 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -20,7 +20,7 @@ const eslintrc = { }, }, parser: '@typescript-eslint/parser', - plugins: ['markdown', 'react', 'babel', 'jest', '@typescript-eslint', 'react-hooks'], + plugins: ['markdown', 'react', 'babel', 'jest', '@typescript-eslint', 'react-hooks', 'unicorn'], // https://github.com/typescript-eslint/typescript-eslint/issues/46#issuecomment-470486034 overrides: [ { @@ -91,6 +91,10 @@ const eslintrc = { 'jest/no-test-callback': 0, 'jest/expect-expect': 0, 'react-hooks/rules-of-hooks': 2, // Checks rules of Hooks + "unicorn/better-regex": 2, + "unicorn/prefer-trim-start-end": 2, + "unicorn/expiring-todo-comments": 2, + "unicorn/no-abusive-eslint-disable": 2, }, globals: { gtag: true, diff --git a/components/_util/wave.tsx b/components/_util/wave.tsx index b3c842770d..457eb8cd43 100644 --- a/components/_util/wave.tsx +++ b/components/_util/wave.tsx @@ -16,7 +16,7 @@ function isHidden(element: HTMLElement) { function isNotGrey(color: string) { // eslint-disable-next-line no-useless-escape - const match = (color || '').match(/rgba?\((\d*), (\d*), (\d*)(, [\.\d]*)?\)/); + const match = (color || '').match(/rgba?\((\d*), (\d*), (\d*)(, [\d.]*)?\)/); if (match && match[1] && match[2] && match[3]) { return !(match[1] === match[2] && match[2] === match[3]); } @@ -76,7 +76,7 @@ export default class Wave extends React.Component<{ insertExtraNode?: boolean }> waveColor !== '#ffffff' && waveColor !== 'rgb(255, 255, 255)' && isNotGrey(waveColor) && - !/rgba\(\d*, \d*, \d*, 0\)/.test(waveColor) && // any transparent rgba color + !/rgba\((?:\d*, ){3}0\)/.test(waveColor) && // any transparent rgba color waveColor !== 'transparent' ) { // Add nonce if CSP exist diff --git a/components/alert/__tests__/index.test.js b/components/alert/__tests__/index.test.js index d7680784ef..209d5c5c00 100644 --- a/components/alert/__tests__/index.test.js +++ b/components/alert/__tests__/index.test.js @@ -60,7 +60,8 @@ describe('Alert', () => { const testIt = process.env.REACT === '15' ? it.skip : it; testIt('ErrorBoundary', () => { - const ThrowError = () => ; // eslint-disable-line + // eslint-disable-next-line react/jsx-no-undef + const ThrowError = () => ; const wrapper = mount( diff --git a/components/button/__tests__/index.test.js b/components/button/__tests__/index.test.js index d08a2f7bc8..848de9b380 100644 --- a/components/button/__tests__/index.test.js +++ b/components/button/__tests__/index.test.js @@ -107,7 +107,6 @@ describe('Button', () => { it('have static property for type detecting', () => { const wrapper = mount(); - // eslint-disable-next-line expect(wrapper.type().__ANT_BUTTON).toBe(true); }); @@ -136,7 +135,6 @@ describe('Button', () => { }); it('should change loading state with delay', () => { - // eslint-disable-next-line class DefaultButton extends Component { state = { loading: false, diff --git a/components/calendar/__tests__/index.test.js b/components/calendar/__tests__/index.test.js index b7a80a3243..6b5b52134d 100644 --- a/components/calendar/__tests__/index.test.js +++ b/components/calendar/__tests__/index.test.js @@ -156,7 +156,7 @@ describe('Calendar', () => { it('Calendar should support locale', () => { MockDate.set(Moment('2018-10-19')); - // eslint-disable-next-line + // eslint-disable-next-line global-require const zhCN = require('../locale/zh_CN').default; const wrapper = mount(); expect(wrapper.render()).toMatchSnapshot(); diff --git a/components/dropdown/__tests__/dropdown-button.test.js b/components/dropdown/__tests__/dropdown-button.test.js index 09c23e2735..ed89ded377 100644 --- a/components/dropdown/__tests__/dropdown-button.test.js +++ b/components/dropdown/__tests__/dropdown-button.test.js @@ -40,7 +40,7 @@ describe('DropdownButton', () => { const dropdownProps = wrapper.find(Dropdown).props(); Object.keys(props).forEach(key => { - expect(dropdownProps[key]).toBe(props[key]); // eslint-disable-line + expect(dropdownProps[key]).toBe(props[key]); }); }); diff --git a/components/form/FormItemLabel.tsx b/components/form/FormItemLabel.tsx index ae4ef3fbc4..ee4df7848f 100644 --- a/components/form/FormItemLabel.tsx +++ b/components/form/FormItemLabel.tsx @@ -48,7 +48,7 @@ const FormItemLabel: React.FC { // https://github.com/ant-design/ant-design/issues/21415 it('Component.props.onChange is null', () => { - // eslint-disable-next-line + // eslint-disable-next-line react/prefer-stateless-function class CustomComponent extends Component { static defaultProps = { onChange: null, diff --git a/components/input/demo/tooltip.md b/components/input/demo/tooltip.md index 84ed2b09f6..9fcda74281 100644 --- a/components/input/demo/tooltip.md +++ b/components/input/demo/tooltip.md @@ -35,7 +35,7 @@ function formatNumber(value) { class NumericInput extends React.Component { onChange = e => { const { value } = e.target; - const reg = /^-?[0-9]*(\.[0-9]*)?$/; + const reg = /^-?\d*(\.\d*)?$/; if ((!isNaN(value) && reg.test(value)) || value === '' || value === '-') { this.props.onChange(value); } diff --git a/components/message/__tests__/index.test.js b/components/message/__tests__/index.test.js index 52db3211d2..efa8fbb998 100644 --- a/components/message/__tests__/index.test.js +++ b/components/message/__tests__/index.test.js @@ -98,7 +98,6 @@ describe('message', () => { // https://github.com/ant-design/ant-design/issues/8201 it('should destroy messages correctly', () => { - // eslint-disable-next-line class Test extends React.Component { componentDidMount() { message.loading('Action in progress1..', 0); diff --git a/components/statistic/utils.tsx b/components/statistic/utils.tsx index 6a0c9f3ae2..ff840041aa 100644 --- a/components/statistic/utils.tsx +++ b/components/statistic/utils.tsx @@ -36,7 +36,7 @@ const timeUnits: [string, number][] = [ export function formatTimeStr(duration: number, format: string) { let leftDuration: number = duration; - const escapeRegex = /\[[^\]]*\]/g; + const escapeRegex = /\[[^\]]*]/g; const keepList: string[] = (format.match(escapeRegex) || []).map(str => str.slice(1, -1)); const templateText = format.replace(escapeRegex, '[]'); diff --git a/components/transfer/index.tsx b/components/transfer/index.tsx index ed51b27115..d5ee5b5b31 100644 --- a/components/transfer/index.tsx +++ b/components/transfer/index.tsx @@ -115,7 +115,7 @@ class Transfer extends React.Component { }; } - // eslint-disable-next-line + // eslint-disable-next-line class-methods-use-this getSelectedKeysName(direction: TransferDirection) { return direction === 'left' ? 'sourceSelectedKeys' : 'targetSelectedKeys'; } diff --git a/components/typography/Editable.tsx b/components/typography/Editable.tsx index 51b8922642..a3dd70eaa8 100644 --- a/components/typography/Editable.tsx +++ b/components/typography/Editable.tsx @@ -55,7 +55,7 @@ class Editable extends React.Component { } onChange: React.ChangeEventHandler = ({ target: { value } }) => { - this.setState({ current: value.replace(/[\r\n]/g, '') }); + this.setState({ current: value.replace(/[\n\r]/g, '') }); }; onCompositionStart = () => { diff --git a/components/typography/__tests__/index.test.js b/components/typography/__tests__/index.test.js index 46473126db..7439edd574 100644 --- a/components/typography/__tests__/index.test.js +++ b/components/typography/__tests__/index.test.js @@ -276,7 +276,7 @@ describe('Typography', () => { wrapper.find('TextArea').simulate('keyUp', { keyCode: KeyCode.ESC }); }, onChange => { - // eslint-disable-next-line + // eslint-disable-next-line jest/no-standalone-expect expect(onChange).not.toHaveBeenCalled(); }, ); diff --git a/components/upload/Upload.tsx b/components/upload/Upload.tsx index 1bbfe6ea3e..a6c09ba823 100644 --- a/components/upload/Upload.tsx +++ b/components/upload/Upload.tsx @@ -165,7 +165,7 @@ class Upload extends React.Component { const removedFileList = removeFileItem(file, fileList); if (removedFileList) { - file.status = 'removed'; // eslint-disable-line + file.status = 'removed'; if (this.upload) { this.upload.abort(file); diff --git a/components/upload/__tests__/upload.test.js b/components/upload/__tests__/upload.test.js index 1263e17218..73ad951cdf 100644 --- a/components/upload/__tests__/upload.test.js +++ b/components/upload/__tests__/upload.test.js @@ -199,7 +199,6 @@ describe('Upload', () => { // https://github.com/ant-design/ant-design/issues/14298 it('should not have id if upload children is null, avoid being triggered by label', () => { - // eslint-disable-next-line const Demo = ({ children }) => (
@@ -221,7 +220,6 @@ describe('Upload', () => { // https://github.com/ant-design/ant-design/issues/16478 it('should not have id if upload is disabled, avoid being triggered by label', () => { - // eslint-disable-next-line const Demo = ({ disabled }) => ( diff --git a/package.json b/package.json index 4ea5832f2f..5edb672ad7 100644 --- a/package.json +++ b/package.json @@ -190,6 +190,7 @@ "eslint-plugin-markdown": "^1.0.0", "eslint-plugin-react": "^7.14.2", "eslint-plugin-react-hooks": "^3.0.0", + "eslint-plugin-unicorn": "^18.0.1", "eslint-tinker": "^0.5.0", "fetch-jsonp": "^1.1.3", "full-icu": "^1.3.0", diff --git a/scripts/check-site.js b/scripts/check-site.js index ddc8a6cf45..98100287a7 100755 --- a/scripts/check-site.js +++ b/scripts/check-site.js @@ -16,7 +16,7 @@ const components = uniq( cwd: join(process.cwd()), dot: false, }) - .map(path => path.replace(/(\/index)?((\.zh-CN)|(\.en-US))?\.md$/i, '')), + .map(path => path.replace(/(\/index)?((\.zh-cn)|(\.en-us))?\.md$/i, '')), ); describe('site test', () => { diff --git a/site/bisheng.config.js b/site/bisheng.config.js index f5119dcd6f..28cd617e31 100644 --- a/site/bisheng.config.js +++ b/site/bisheng.config.js @@ -14,7 +14,6 @@ function alertBabelConfig(rules) { if (rule.options.plugins.indexOf(replaceLib) === -1) { rule.options.plugins.push(replaceLib); } - // eslint-disable-next-line rule.options.plugins = rule.options.plugins.filter( plugin => !plugin.indexOf || plugin.indexOf('babel-plugin-add-module-exports') === -1, ); @@ -106,7 +105,6 @@ module.exports = { javascriptEnabled: true, }, webpackConfig(config) { - // eslint-disable-next-line config.resolve.alias = { 'antd/lib': path.join(process.cwd(), 'components'), 'antd/es': path.join(process.cwd(), 'components'), @@ -116,23 +114,21 @@ module.exports = { 'react-intl': 'react-intl/dist', }; - // eslint-disable-next-line config.externals = { 'react-router-dom': 'ReactRouterDOM', }; if (usePreact) { - // eslint-disable-next-line - config.resolve.alias = Object.assign({}, config.resolve.alias, { + config.resolve.alias = { + ...config.resolve.alias, react: 'preact-compat', 'react-dom': 'preact-compat', 'create-react-class': 'preact-compat/lib/create-react-class', 'react-router': 'react-router', - }); + }; } if (isDev) { - // eslint-disable-next-line config.devtool = 'source-map'; // Resolve use react hook fail when yarn link or npm link diff --git a/site/theme/template/Color/ColorPaletteTool.jsx b/site/theme/template/Color/ColorPaletteTool.jsx index 181837f661..3030210de0 100644 --- a/site/theme/template/Color/ColorPaletteTool.jsx +++ b/site/theme/template/Color/ColorPaletteTool.jsx @@ -6,7 +6,6 @@ import ColorPatterns from './ColorPatterns'; const primaryMinSaturation = 70; // 主色推荐最小饱和度 const primaryMinBrightness = 70; // 主色推荐最小亮度 -// eslint-disable-next-line export default class ColorPaletteTool extends Component { state = { primaryColor: '#1890ff', diff --git a/site/theme/template/Color/ColorPaletteToolDark.jsx b/site/theme/template/Color/ColorPaletteToolDark.jsx index 1f82883824..46ea8cedaa 100644 --- a/site/theme/template/Color/ColorPaletteToolDark.jsx +++ b/site/theme/template/Color/ColorPaletteToolDark.jsx @@ -7,7 +7,6 @@ import ColorPatterns from './ColorPatterns'; const primaryMinSaturation = 70; // 主色推荐最小饱和度 const primaryMinBrightness = 70; // 主色推荐最小亮度 -// eslint-disable-next-line export default class ColorPaletteTool extends Component { state = { primaryColor: '#1890ff', diff --git a/site/theme/template/Content/Article.tsx b/site/theme/template/Content/Article.tsx index 37da84c944..5eb1e37118 100644 --- a/site/theme/template/Content/Article.tsx +++ b/site/theme/template/Content/Article.tsx @@ -109,7 +109,6 @@ class Article extends React.Component { const metaDesc = helmetDesc || contentChild; return ( - /* eslint-disable-next-line */
{helmetTitle && {helmetTitle}} diff --git a/site/theme/template/Content/Demo/index.jsx b/site/theme/template/Content/Demo/index.jsx index 6373206592..f847109935 100644 --- a/site/theme/template/Content/Demo/index.jsx +++ b/site/theme/template/Content/Demo/index.jsx @@ -92,7 +92,7 @@ class Demo extends React.Component { }); }; - // eslint-disable-next-line + // eslint-disable-next-line class-methods-use-this track({ type, demo }) { if (!window.gtag) { return; @@ -180,18 +180,18 @@ class Demo extends React.Component { title: `${localizedTitle} - Ant Design Demo`, html, js: sourceCode - .replace(/import\s+\{(\s+[^}]*\s+)\}\s+from\s+'antd';/, 'const { $1 } = antd;') + .replace(/import\s+{(\s+[^}]*\s+)}\s+from\s+'antd';/, 'const { $1 } = antd;') .replace( - /import\s+\{(\s+[^}]*\s+)\}\s+from\s+'@ant-design\/icons';/, + /import\s+{(\s+[^}]*\s+)}\s+from\s+'@ant-design\/icons';/, 'const { $1 } = icons;', ) .replace("import moment from 'moment';", '') - .replace(/import\s+\{\s+(.*)\s+\}\s+from\s+'react-router';/, 'const { $1 } = ReactRouter;') + .replace(/import\s+{\s+(.*)\s+}\s+from\s+'react-router';/, 'const { $1 } = ReactRouter;') .replace( - /import\s+\{\s+(.*)\s+\}\s+from\s+'react-router-dom';/, + /import\s+{\s+(.*)\s+}\s+from\s+'react-router-dom';/, 'const { $1 } = ReactRouterDOM;', ) - .replace(/([a-zA-Z]*)\s+as\s+([a-zA-Z]*)/, '$1:$2'), + .replace(/([A-Za-z]*)\s+as\s+([A-Za-z]*)/, '$1:$2'), css: prefillStyle, editors: '001', // eslint-disable-next-line no-undef @@ -300,7 +300,7 @@ ${parsedSourceCode.replace('mountNode', "document.getElementById('container')")}
{this.liveDemo} {style ? ( -