1- import {
2- TSESTree ,
3- AST_NODE_TYPES ,
4- } from '@typescript-eslint/experimental-utils' ;
1+ import { TSESTree } from '@typescript-eslint/experimental-utils' ;
52import 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' ;
79
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 > ;
1012
11- export default util . createRule < Options , MessageIds > ( {
13+ export default createRule < Options , MessageIds > ( {
1214 name : 'brace-style' ,
1315 meta : {
1416 type : 'layout' ,
@@ -23,23 +25,117 @@ export default util.createRule<Options, MessageIds>({
2325 } ,
2426 defaultOptions : [ '1tbs' ] ,
2527 create ( context ) {
28+ const [
29+ style ,
30+ { allowSingleLine } = { allowSingleLine : false } ,
31+ ] = context . options ;
32+
33+ const isAllmanStyle = style === 'allman' ;
34+ const sourceCode = context . getSourceCode ( ) ;
2635 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+ }
38120
39121 return {
40122 ...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+ } ,
43139 } ;
44140 } ,
45141} ) ;
0 commit comments