From 0ab9f886038de2322c1b2f6dd35b447e99cce93d Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Mon, 25 Apr 2022 13:26:07 +0800 Subject: [PATCH] feat(eslint-plugin): new import dedupe rule --- packages/basic/index.js | 10 ++-- packages/eslint-plugin-antfu/.eslintrc.json | 5 +- packages/eslint-plugin-antfu/src/index.ts | 4 +- ...-newline.test.ts => import-dedupe.test.ts} | 17 +++--- .../src/rules/import-dedupe.ts | 55 +++++++++++++++++++ .../src/rules/no-leading-newline.ts | 44 --------------- 6 files changed, 72 insertions(+), 63 deletions(-) rename packages/eslint-plugin-antfu/src/rules/{no-leading-newline.test.ts => import-dedupe.test.ts} (53%) create mode 100644 packages/eslint-plugin-antfu/src/rules/import-dedupe.ts delete mode 100644 packages/eslint-plugin-antfu/src/rules/no-leading-newline.ts diff --git a/packages/basic/index.js b/packages/basic/index.js index 3c0b516..9ba5532 100644 --- a/packages/basic/index.js +++ b/packages/basic/index.js @@ -186,10 +186,10 @@ module.exports = { 'space-before-function-paren': [ 'error', { - 'anonymous': 'always', - 'named': 'never', - 'asyncArrow': 'always' - } + anonymous: 'always', + named: 'never', + asyncArrow: 'always', + }, ], 'no-multiple-empty-lines': ['error', { max: 1, maxBOF: 0, maxEOF: 1 }], @@ -300,8 +300,8 @@ module.exports = { 'yml/no-empty-document': 'off', // antfu - // 'antfu/no-leading-newline': 'error', 'antfu/if-newline': 'error', + 'antfu/import-dedupe': 'error', // 'antfu/prefer-inline-type-import': 'error', }, } diff --git a/packages/eslint-plugin-antfu/.eslintrc.json b/packages/eslint-plugin-antfu/.eslintrc.json index ccf50ef..573a5dc 100644 --- a/packages/eslint-plugin-antfu/.eslintrc.json +++ b/packages/eslint-plugin-antfu/.eslintrc.json @@ -2,8 +2,5 @@ "extends": "@antfu", "plugins": [ "antfu" - ], - "rules": { - "antfu/no-leading-newline": "error" - } + ] } diff --git a/packages/eslint-plugin-antfu/src/index.ts b/packages/eslint-plugin-antfu/src/index.ts index 05db2be..89d2333 100644 --- a/packages/eslint-plugin-antfu/src/index.ts +++ b/packages/eslint-plugin-antfu/src/index.ts @@ -1,11 +1,11 @@ import ifNewline from './rules/if-newline' -import noLeadingNewline from './rules/no-leading-newline' +import importDedupe from './rules/import-dedupe' import preferInlineTypeImport from './rules/prefer-inline-type-import' export default { rules: { - 'no-leading-newline': noLeadingNewline, 'if-newline': ifNewline, + 'import-dedupe': importDedupe, 'prefer-inline-type-import': preferInlineTypeImport, }, } diff --git a/packages/eslint-plugin-antfu/src/rules/no-leading-newline.test.ts b/packages/eslint-plugin-antfu/src/rules/import-dedupe.test.ts similarity index 53% rename from packages/eslint-plugin-antfu/src/rules/no-leading-newline.test.ts rename to packages/eslint-plugin-antfu/src/rules/import-dedupe.test.ts index 22f1719..3341c44 100644 --- a/packages/eslint-plugin-antfu/src/rules/no-leading-newline.test.ts +++ b/packages/eslint-plugin-antfu/src/rules/import-dedupe.test.ts @@ -1,14 +1,15 @@ import { RuleTester } from '@typescript-eslint/utils/dist/ts-eslint' import { it } from 'vitest' -import rule, { RULE_NAME } from './no-leading-newline' +import rule, { RULE_NAME } from './import-dedupe' const valids = [ - 'import {} from \'foo\'', - `// comment -import {} from ''`, + 'import { a } from \'foo\'', ] const invalids = [ - '\n\nimport {} from \'fo\'', + [ + 'import { a, b, a, a, c, a } from \'foo\'', + 'import { a, b, c, } from \'foo\'', + ], ] it('runs', () => { @@ -19,9 +20,9 @@ it('runs', () => { ruleTester.run(RULE_NAME, rule, { valid: valids, invalid: invalids.map(i => ({ - code: i, - output: i.trim(), - errors: [{ messageId: 'noLeadingNewline' }], + code: i[0], + output: i[1], + errors: [{ messageId: 'importDedupe' }, { messageId: 'importDedupe' }, { messageId: 'importDedupe' }], })), }) }) diff --git a/packages/eslint-plugin-antfu/src/rules/import-dedupe.ts b/packages/eslint-plugin-antfu/src/rules/import-dedupe.ts new file mode 100644 index 0000000..3a4f4f5 --- /dev/null +++ b/packages/eslint-plugin-antfu/src/rules/import-dedupe.ts @@ -0,0 +1,55 @@ +import { createEslintRule } from '../utils' + +export const RULE_NAME = 'import-dedupe' +export type MessageIds = 'importDedupe' +export type Options = [] + +export default createEslintRule({ + name: RULE_NAME, + meta: { + type: 'problem', + docs: { + description: 'Fix duplication in imports', + recommended: 'error', + }, + fixable: 'code', + schema: [], + messages: { + importDedupe: 'Expect no duplication in imports', + }, + }, + defaultOptions: [], + create: (context) => { + return { + ImportDeclaration(node) { + if (node.specifiers.length <= 1) + return + + const names = new Set() + node.specifiers.forEach((n) => { + const id = n.local.name + if (names.has(id)) { + context.report({ + node, + loc: { + start: n.loc.end, + end: n.loc.start, + }, + messageId: 'importDedupe', + fix(fixer) { + const s = n.range[0] + let e = n.range[1] + if (context.getSourceCode().text[e] === ',') + e += 1 + return fixer.removeRange([s, e]) + }, + }) + } + names.add(id) + }) + + // console.log(node) + }, + } + }, +}) diff --git a/packages/eslint-plugin-antfu/src/rules/no-leading-newline.ts b/packages/eslint-plugin-antfu/src/rules/no-leading-newline.ts deleted file mode 100644 index 416e80a..0000000 --- a/packages/eslint-plugin-antfu/src/rules/no-leading-newline.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { createEslintRule } from '../utils' - -export const RULE_NAME = 'no-leading-newline' -export type MessageIds = 'noLeadingNewline' -export type Options = [] - -export default createEslintRule({ - name: RULE_NAME, - meta: { - type: 'problem', - docs: { - description: 'Do not allow leading newline', - recommended: 'error', - }, - fixable: 'whitespace', - schema: [], - messages: { - noLeadingNewline: 'No leading newline allowed', - }, - }, - defaultOptions: [], - create: (context) => { - return { - Program(node) { - const code = context.getSourceCode() - const match = code.text.match(/^[\s]+/)?.[0] || '' - if (match.includes('\n')) { - const line = match.split('\n') - context.report({ - node, - loc: { - start: { line: 0, column: 0 }, - end: { line: line.length - 1, column: line[line.length - 1].length }, - }, - messageId: 'noLeadingNewline', - fix(fixer) { - return fixer.replaceTextRange([0, match.length], '') - }, - }) - } - }, - } - }, -})