diff --git a/packages/eslint-plugin-antfu/package.json b/packages/eslint-plugin-antfu/package.json index 4b79318a8c..d0eff5d707 100644 --- a/packages/eslint-plugin-antfu/package.json +++ b/packages/eslint-plugin-antfu/package.json @@ -16,7 +16,7 @@ "prepublishOnly": "nr build" }, "dependencies": { - "@typescript-eslint/utils": "^6.0.0" + "@typescript-eslint/utils": "^5.61.0" }, "devDependencies": { "@types/node": "^20.4.2", diff --git a/packages/eslint-plugin-antfu/src/rules/named-tuple-spacing.test.ts b/packages/eslint-plugin-antfu/src/rules/named-tuple-spacing.test.ts index 1c2292e2d3..073cf79222 100644 --- a/packages/eslint-plugin-antfu/src/rules/named-tuple-spacing.test.ts +++ b/packages/eslint-plugin-antfu/src/rules/named-tuple-spacing.test.ts @@ -1,11 +1,10 @@ import { RuleTester } from '@typescript-eslint/utils/dist/ts-eslint' import { it } from 'vitest' -import type { MessageIds } from './named-tuple-spacing' import rule, { RULE_NAME } from './named-tuple-spacing' const valids = [ 'type T = [i: number]', - 'type T = [i: number]', // passes since it will be handled by eslint's no-multi-spaces + 'type T = [i?: number]', 'type T = [i: number, j: number]', `const emit = defineEmits<{ change: [id: number] @@ -13,23 +12,6 @@ const valids = [ }>()`, ] -const invalids = [ - ['type T = [i:number]', 'type T = [i: number]'], - ['type T = [i : number]', 'type T = [i: number]', 1, 'unexpectedSpaceBefore'], - ['type T = [i:number, j:number]', 'type T = [i: number, j: number]', 2], - [ - `const emit = defineEmits<{ - change: [id:number] - update: [value:string] - }>()`, - `const emit = defineEmits<{ - change: [id: number] - update: [value: string] - }>()`, - 2, - ], -] as [error: string, correct: string, errorNumber: number | undefined, errorMsg: MessageIds | undefined][] - it('runs', () => { const ruleTester: RuleTester = new RuleTester({ parser: require.resolve('@typescript-eslint/parser'), @@ -37,10 +19,77 @@ it('runs', () => { ruleTester.run(RULE_NAME, rule, { valid: valids, - invalid: invalids.map(i => ({ - code: i[0], - output: i[1].trim(), - errors: Array.from({ length: i[2] || 1 }, () => ({ messageId: i[3] || 'expectedSpaceAfter' })), - })), + invalid: [ + { + code: 'type T = [i:number]', + output: 'type T = [i: number]', + errors: [{ messageId: 'expectedSpaceAfter' }], + }, + { + code: 'type T = [i: number]', + output: 'type T = [i: number]', + errors: [{ messageId: 'expectedSpaceAfter' }], + }, + { + code: 'type T = [i?:number]', + output: 'type T = [i?: number]', + errors: [{ messageId: 'expectedSpaceAfter' }], + }, + { + code: 'type T = [i? :number]', + output: 'type T = [i?: number]', + errors: [{ messageId: 'unexpectedSpaceBetween' }, { messageId: 'expectedSpaceAfter' }], + }, + { + code: 'type T = [i : number]', + output: 'type T = [i: number]', + errors: [{ messageId: 'unexpectedSpaceBefore' }], + }, + { + code: 'type T = [i : number]', + output: 'type T = [i: number]', + errors: [{ messageId: 'unexpectedSpaceBefore' }], + }, + { + code: 'type T = [i ? : number]', + output: 'type T = [i?: number]', + errors: [{ messageId: 'unexpectedSpaceBetween' }, { messageId: 'unexpectedSpaceBefore' }], + }, + { + code: 'type T = [i:number, j:number]', + output: 'type T = [i: number, j: number]', + errors: [{ messageId: 'expectedSpaceAfter' }, { messageId: 'expectedSpaceAfter' }], + }, + { + code: ` + const emit = defineEmits<{ + change: [id:number] + update: [value:string] + }>() + `, + output: ` + const emit = defineEmits<{ + change: [id: number] + update: [value: string] + }>() + `, + errors: [{ messageId: 'expectedSpaceAfter' }, { messageId: 'expectedSpaceAfter' }], + }, + { + code: ` + const emit = defineEmits<{ + change: [id? :number] + update: [value:string] + }>() + `, + output: ` + const emit = defineEmits<{ + change: [id?: number] + update: [value: string] + }>() + `, + errors: [{ messageId: 'unexpectedSpaceBetween' }, { messageId: 'expectedSpaceAfter' }, { messageId: 'expectedSpaceAfter' }], + }, + ], }) }) diff --git a/packages/eslint-plugin-antfu/src/rules/named-tuple-spacing.ts b/packages/eslint-plugin-antfu/src/rules/named-tuple-spacing.ts index d41fc30dcf..069cce0bc8 100644 --- a/packages/eslint-plugin-antfu/src/rules/named-tuple-spacing.ts +++ b/packages/eslint-plugin-antfu/src/rules/named-tuple-spacing.ts @@ -1,7 +1,7 @@ import { createEslintRule } from '../utils' export const RULE_NAME = 'named-tuple-spacing' -export type MessageIds = 'expectedSpaceAfter' | 'unexpectedSpaceBefore' +export type MessageIds = 'expectedSpaceAfter' | 'unexpectedSpaceBetween' | 'unexpectedSpaceBefore' export type Options = [] export default createEslintRule({ @@ -16,36 +16,60 @@ export default createEslintRule({ schema: [], messages: { expectedSpaceAfter: 'Expected a space after the \':\'.', - unexpectedSpaceBefore: 'Unexpected space(s) before the \':\'.', + unexpectedSpaceBetween: 'Unexpected space between \'?\' and the \':\'.', + unexpectedSpaceBefore: 'Unexpected space before the \':\'.', }, }, defaultOptions: [], create: (context) => { const sourceCode = context.getSourceCode() return { - TSNamedTupleMember: (node) => { + TSNamedTupleMember: (node: any) => { const code = sourceCode.text.slice(node.range[0], node.range[1]) - const reg = /(\w+)( *):( *)(\w+)/ - const spacesBeforeColon = code.match(reg)?.[2] - const spacesAfterColon = code.match(reg)?.[3] + const reg = /(\w+)(\s*)(\?\s*)?:(\s*)(\w+)/ - if (spacesBeforeColon?.length) { + const labelName = node.label.name + const spaceBeforeColon = code.match(reg)?.[2] + const optionalMark = code.match(reg)?.[3] + const spacesAfterColon = code.match(reg)?.[4] + const elementType = code.match(reg)?.[5] + + function getReplaceValue() { + let ret = labelName + if (node.optional) + ret += '?' + ret += ': ' + ret += elementType + return ret + } + + if (optionalMark?.length > 1) { + context.report({ + node, + messageId: 'unexpectedSpaceBetween', + *fix(fixer) { + yield fixer.replaceTextRange(node.range, code.replace(reg, getReplaceValue())) + }, + }) + } + + if (spaceBeforeColon?.length) { context.report({ node, messageId: 'unexpectedSpaceBefore', *fix(fixer) { - yield fixer.replaceTextRange(node.range, code.replace(reg, '$1: $4')) + yield fixer.replaceTextRange(node.range, code.replace(reg, getReplaceValue())) }, }) } - if (!spacesAfterColon) { + if (spacesAfterColon.length !== 1) { context.report({ node, messageId: 'expectedSpaceAfter', *fix(fixer) { - yield fixer.replaceTextRange(node.range, code.replace(reg, '$1: $4')) + yield fixer.replaceTextRange(node.range, code.replace(reg, getReplaceValue())) }, }) } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9aae17dd94..2344e64354 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -191,8 +191,8 @@ importers: packages/eslint-plugin-antfu: dependencies: '@typescript-eslint/utils': - specifier: ^6.0.0 - version: 6.0.0(eslint@8.45.0)(typescript@5.1.6) + specifier: ^5.61.0 + version: 5.61.0(eslint@8.45.0)(typescript@5.1.6) devDependencies: '@types/node': specifier: ^20.4.2 @@ -1075,13 +1075,34 @@ packages: debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 - semver: 7.5.3 + semver: 7.5.4 tsutils: 3.21.0(typescript@5.0.2) typescript: 5.0.2 transitivePeerDependencies: - supports-color dev: false + /@typescript-eslint/typescript-estree@5.61.0(typescript@5.1.6): + resolution: {integrity: sha512-Fud90PxONnnLZ36oR5ClJBLTLfU4pIWBmnvGwTbEa2cXIqj70AEDEmOmpkFComjBZ/037ueKrOdHuYmSFVD7Rw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 5.61.0 + '@typescript-eslint/visitor-keys': 5.61.0 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.5.4 + tsutils: 3.21.0(typescript@5.1.6) + typescript: 5.1.6 + transitivePeerDependencies: + - supports-color + dev: false + /@typescript-eslint/typescript-estree@6.0.0(typescript@5.0.2): resolution: {integrity: sha512-2zq4O7P6YCQADfmJ5OTDQTP3ktajnXIRrYAtHM9ofto/CJZV3QfJ89GEaM2BNGeSr1KgmBuLhEkz5FBkS2RQhQ==} engines: {node: ^16.0.0 || >=18.0.0} @@ -1138,7 +1159,27 @@ packages: '@typescript-eslint/typescript-estree': 5.61.0(typescript@5.0.2) eslint: 8.45.0 eslint-scope: 5.1.1 - semver: 7.5.3 + semver: 7.5.4 + transitivePeerDependencies: + - supports-color + - typescript + dev: false + + /@typescript-eslint/utils@5.61.0(eslint@8.45.0)(typescript@5.1.6): + resolution: {integrity: sha512-mV6O+6VgQmVE6+xzlA91xifndPW9ElFW8vbSF0xCT/czPXVhwDewKila1jOyRwa9AE19zKnrr7Cg5S3pJVrTWQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.45.0) + '@types/json-schema': 7.0.11 + '@types/semver': 7.3.13 + '@typescript-eslint/scope-manager': 5.61.0 + '@typescript-eslint/types': 5.61.0 + '@typescript-eslint/typescript-estree': 5.61.0(typescript@5.1.6) + eslint: 8.45.0 + eslint-scope: 5.1.1 + semver: 7.5.4 transitivePeerDependencies: - supports-color - typescript @@ -1933,7 +1974,7 @@ packages: is-glob: 4.0.3 minimatch: 3.1.2 resolve: 1.22.3 - semver: 7.5.3 + semver: 7.5.4 transitivePeerDependencies: - '@typescript-eslint/parser' - eslint-import-resolver-typescript @@ -3877,6 +3918,16 @@ packages: typescript: 5.0.2 dev: false + /tsutils@3.21.0(typescript@5.1.6): + resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} + engines: {node: '>= 6'} + peerDependencies: + typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + dependencies: + tslib: 1.14.1 + typescript: 5.1.6 + dev: false + /type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'}