Skip to content
Permalink
Browse files
feat: format for generics spacing
  • Loading branch information
antfu committed Oct 31, 2022
1 parent 3c12076 commit 588494cc01748961ac69651715f12e80a28fe327
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 71 deletions.
@@ -19,6 +19,7 @@
"@typescript-eslint/utils": "^5.36.1"
},
"devDependencies": {
"@types/node": "^18.11.8",
"unbuild": "^0.8.10",
"vitest": "^0.22.1"
}
@@ -1,3 +1,4 @@
import genericSpacing from './rules/generic-spacing'
import ifNewline from './rules/if-newline'
import importDedupe from './rules/import-dedupe'
import preferInlineTypeImport from './rules/prefer-inline-type-import'
@@ -7,5 +8,6 @@ export default {
'if-newline': ifNewline,
'import-dedupe': importDedupe,
'prefer-inline-type-import': preferInlineTypeImport,
'generic-spacing': genericSpacing,
},
}
@@ -0,0 +1,32 @@
import { RuleTester } from '@typescript-eslint/utils/dist/ts-eslint'
import { it } from 'vitest'
import rule, { RULE_NAME } from './generic-spacing'

const valids = [
'type Foo<T = true> = T',
`
type Foo<
T = true,
K = false
> = T`,
]
const invalids = [
['type Foo<T=true> = T', 'type Foo<T = true> = T'],
['type Foo<T,K> = T', 'type Foo<T, K> = T'],
['type Foo<T=false,K=1|2> = T', 'type Foo<T = false, K = 1|2> = T', 3],
] as const

it('runs', () => {
const ruleTester: RuleTester = new RuleTester({
parser: require.resolve('@typescript-eslint/parser'),
})

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: 'genericSpacingMismatch' })),
})),
})
})
@@ -0,0 +1,69 @@
import { createEslintRule } from '../utils'

export const RULE_NAME = 'generic-spacing'
export type MessageIds = 'genericSpacingMismatch'
export type Options = []

export default createEslintRule<Options, MessageIds>({
name: RULE_NAME,
meta: {
type: 'suggestion',
docs: {
description: 'Spaces around generic type parameters',
recommended: 'error',
},
fixable: 'code',
schema: [],
messages: {
genericSpacingMismatch: 'Generic spaces mismatch',
},
},
defaultOptions: [],
create: (context) => {
const sourceCode = context.getSourceCode()
return {
TSTypeParameterDeclaration: (node) => {
const params = node.params
for (let i = 1; i < params.length; i++) {
const prev = params[i - 1]
const current = params[i]
const from = prev.range[1]
const to = current.range[0]
const span = sourceCode.text.slice(from, to)
if (span !== ', ' && !span.match(/,\n/)) {
context.report({
*fix(fixer) {
yield fixer.replaceTextRange([from, to], ', ')
},
loc: {
start: prev.loc.end,
end: current.loc.start,
},
messageId: 'genericSpacingMismatch',
node,
})
}
}
},
TSTypeParameter: (node) => {
if (!node.default)
return
const from = node.name.range[1]
const to = node.default.range[0]
if (sourceCode.text.slice(from, to) !== ' = ') {
context.report({
*fix(fixer) {
yield fixer.replaceTextRange([from, to], ' = ')
},
loc: {
start: node.name.loc.end,
end: node.default.loc.start,
},
messageId: 'genericSpacingMismatch',
node,
})
}
},
}
},
})
@@ -106,6 +106,9 @@ module.exports = {
'lines-between-class-members': 'off',
'@typescript-eslint/lines-between-class-members': ['error', 'always', { exceptAfterSingleLine: true }],

// antfu
'antfu/generic-spacing': 'error',

// The following rule overrides require a parser service, aka. require a `typescript.json` path.
// This needs to be done individually for each project, and it slows down linting significantly.
// 'no-throw-literal': 'off',

0 comments on commit 588494c

Please sign in to comment.