1
- import {
2
- TSESTree ,
3
- AST_NODE_TYPES ,
4
- } from '@typescript-eslint/experimental-utils' ;
1
+ import { TSESTree } from '@typescript-eslint/experimental-utils' ;
5
2
import baseRule from 'eslint/lib/rules/brace-style' ;
6
- import * as util from '../util' ;
3
+ import {
4
+ InferOptionsTypeFromRule ,
5
+ InferMessageIdsTypeFromRule ,
6
+ createRule ,
7
+ isTokenOnSameLine ,
8
+ } from '../util' ;
7
9
8
- export type Options = util . InferOptionsTypeFromRule < typeof baseRule > ;
9
- export type MessageIds = util . InferMessageIdsTypeFromRule < typeof baseRule > ;
10
+ export type Options = InferOptionsTypeFromRule < typeof baseRule > ;
11
+ export type MessageIds = InferMessageIdsTypeFromRule < typeof baseRule > ;
10
12
11
- export default util . createRule < Options , MessageIds > ( {
13
+ export default createRule < Options , MessageIds > ( {
12
14
name : 'brace-style' ,
13
15
meta : {
14
16
type : 'layout' ,
@@ -23,23 +25,117 @@ export default util.createRule<Options, MessageIds>({
23
25
} ,
24
26
defaultOptions : [ '1tbs' ] ,
25
27
create ( context ) {
28
+ const [
29
+ style ,
30
+ { allowSingleLine } = { allowSingleLine : false } ,
31
+ ] = context . options ;
32
+
33
+ const isAllmanStyle = style === 'allman' ;
34
+ const sourceCode = context . getSourceCode ( ) ;
26
35
const rules = baseRule . create ( context ) ;
27
- const checkBlockStatement = (
28
- node : TSESTree . TSModuleBlock | TSESTree . TSInterfaceBody ,
29
- ) : void => {
30
- rules . BlockStatement ( {
31
- type : AST_NODE_TYPES . BlockStatement ,
32
- parent : node . parent ,
33
- range : node . range ,
34
- body : node . body as any , // eslint-disable-line @typescript-eslint/no-explicit-any
35
- loc : node . loc ,
36
- } ) ;
37
- } ;
36
+
37
+ /**
38
+ * Checks a pair of curly brackets based on the user's config
39
+ */
40
+ function validateCurlyPair (
41
+ openingCurlyToken : TSESTree . Token ,
42
+ closingCurlyToken : TSESTree . Token ,
43
+ ) : void {
44
+ if (
45
+ allowSingleLine &&
46
+ isTokenOnSameLine ( openingCurlyToken , closingCurlyToken )
47
+ ) {
48
+ return ;
49
+ }
50
+
51
+ const tokenBeforeOpeningCurly = sourceCode . getTokenBefore (
52
+ openingCurlyToken ,
53
+ ) ! ;
54
+ const tokenBeforeClosingCurly = sourceCode . getTokenBefore (
55
+ closingCurlyToken ,
56
+ ) ! ;
57
+ const tokenAfterOpeningCurly = sourceCode . getTokenAfter (
58
+ openingCurlyToken ,
59
+ ) ! ;
60
+
61
+ if (
62
+ ! isAllmanStyle &&
63
+ ! isTokenOnSameLine ( tokenBeforeOpeningCurly , openingCurlyToken )
64
+ ) {
65
+ context . report ( {
66
+ node : openingCurlyToken ,
67
+ messageId : 'nextLineOpen' ,
68
+ fix : fixer => {
69
+ const textRange : TSESTree . Range = [
70
+ tokenBeforeOpeningCurly . range [ 1 ] ,
71
+ openingCurlyToken . range [ 0 ] ,
72
+ ] ;
73
+ const textBetween = sourceCode . text . slice (
74
+ textRange [ 0 ] ,
75
+ textRange [ 1 ] ,
76
+ ) ;
77
+
78
+ if ( textBetween . trim ( ) ) {
79
+ return null ;
80
+ }
81
+
82
+ return fixer . replaceTextRange ( textRange , ' ' ) ;
83
+ } ,
84
+ } ) ;
85
+ }
86
+
87
+ if (
88
+ isAllmanStyle &&
89
+ isTokenOnSameLine ( tokenBeforeOpeningCurly , openingCurlyToken )
90
+ ) {
91
+ context . report ( {
92
+ node : openingCurlyToken ,
93
+ messageId : 'sameLineOpen' ,
94
+ fix : fixer => fixer . insertTextBefore ( openingCurlyToken , '\n' ) ,
95
+ } ) ;
96
+ }
97
+
98
+ if (
99
+ isTokenOnSameLine ( openingCurlyToken , tokenAfterOpeningCurly ) &&
100
+ tokenAfterOpeningCurly !== closingCurlyToken
101
+ ) {
102
+ context . report ( {
103
+ node : openingCurlyToken ,
104
+ messageId : 'blockSameLine' ,
105
+ fix : fixer => fixer . insertTextAfter ( openingCurlyToken , '\n' ) ,
106
+ } ) ;
107
+ }
108
+
109
+ if (
110
+ isTokenOnSameLine ( tokenBeforeClosingCurly , closingCurlyToken ) &&
111
+ tokenBeforeClosingCurly !== openingCurlyToken
112
+ ) {
113
+ context . report ( {
114
+ node : closingCurlyToken ,
115
+ messageId : 'singleLineClose' ,
116
+ fix : fixer => fixer . insertTextBefore ( closingCurlyToken , '\n' ) ,
117
+ } ) ;
118
+ }
119
+ }
38
120
39
121
return {
40
122
...rules ,
41
- TSInterfaceBody : checkBlockStatement ,
42
- TSModuleBlock : checkBlockStatement ,
123
+ 'TSInterfaceBody, TSModuleBlock' (
124
+ node : TSESTree . TSModuleBlock | TSESTree . TSInterfaceBody ,
125
+ ) : void {
126
+ const openingCurly = sourceCode . getFirstToken ( node ) ! ;
127
+ const closingCurly = sourceCode . getLastToken ( node ) ! ;
128
+
129
+ validateCurlyPair ( openingCurly , closingCurly ) ;
130
+ } ,
131
+ TSEnumDeclaration ( node ) : void {
132
+ const closingCurly = sourceCode . getLastToken ( node ) ! ;
133
+ const openingCurly = sourceCode . getTokenBefore (
134
+ node . members . length ? node . members [ 0 ] : closingCurly ,
135
+ ) ! ;
136
+
137
+ validateCurlyPair ( openingCurly , closingCurly ) ;
138
+ } ,
43
139
} ;
44
140
} ,
45
141
} ) ;
0 commit comments