@@ -13,9 +13,11 @@ module.exports = createRule({
13
13
internalCommentNotLastError : `@internal should only appear in final JSDoc comment for declaration.` ,
14
14
multipleJSDocError : `Declaration has multiple JSDoc comments.` ,
15
15
internalCommentOnParameterProperty : `@internal cannot appear on a JSDoc comment; use a declared property and an assignment in the constructor instead.` ,
16
+ misalignedJSDocComment : `This JSDoc comment is misaligned.` ,
16
17
} ,
17
18
schema : [ ] ,
18
19
type : "problem" ,
20
+ fixable : "whitespace" ,
19
21
} ,
20
22
defaultOptions : [ ] ,
21
23
@@ -24,6 +26,11 @@ module.exports = createRule({
24
26
const atInternal = "@internal" ;
25
27
const jsdocStart = "/**" ;
26
28
29
+ /** @type {(text: string) => boolean } */
30
+ function isJSDocText ( text ) {
31
+ return text . startsWith ( jsdocStart ) ;
32
+ }
33
+
27
34
/** @type {(c: TSESTree.Comment, indexInComment: number) => TSESTree.SourceLocation } */
28
35
const getAtInternalLoc = ( c , indexInComment ) => {
29
36
const line = c . loc . start . line ;
@@ -51,7 +58,7 @@ module.exports = createRule({
51
58
} ;
52
59
53
60
/** @type {(node: TSESTree.Node) => void } */
54
- const checkJSDocFormat = ( node ) => {
61
+ const checkDeclaration = ( node ) => {
55
62
const blockComments = sourceCode . getCommentsBefore ( node ) . filter ( c => c . type === "Block" ) ;
56
63
if ( blockComments . length === 0 ) {
57
64
return ;
@@ -63,7 +70,7 @@ module.exports = createRule({
63
70
const c = blockComments [ i ] ;
64
71
const rawComment = sourceCode . getText ( c ) ;
65
72
66
- const isJSDoc = rawComment . startsWith ( jsdocStart ) ;
73
+ const isJSDoc = isJSDocText ( rawComment ) ;
67
74
if ( isJSDoc && seenJSDoc ) {
68
75
context . report ( { messageId : "multipleJSDocError" , node : c , loc : getJSDocStartLoc ( c ) } ) ;
69
76
}
@@ -86,25 +93,85 @@ module.exports = createRule({
86
93
}
87
94
} ;
88
95
96
+ /** @type {(node: TSESTree.Node) => void } */
97
+ const checkProgram = ( ) => {
98
+ const comments = sourceCode . getAllComments ( ) ;
99
+
100
+ for ( const c of comments ) {
101
+ if ( c . type !== "Block" ) {
102
+ continue ;
103
+ }
104
+
105
+ const rawComment = sourceCode . getText ( c ) ;
106
+ if ( ! isJSDocText ( rawComment ) ) {
107
+ continue ;
108
+ }
109
+
110
+ const expected = c . loc . start . column + 2 ;
111
+ const split = rawComment . split ( / \r ? \n / g) ;
112
+ for ( let i = 1 ; i < split . length ; i ++ ) {
113
+ const line = split [ i ] ;
114
+ const match = / ^ * \* / . exec ( line ) ;
115
+ if ( ! match ) {
116
+ continue ;
117
+ }
118
+
119
+ const actual = match [ 0 ] . length ;
120
+ const diff = actual - expected ;
121
+ if ( diff !== 0 ) {
122
+ const line = c . loc . start . line + i ;
123
+ context . report ( {
124
+ messageId : "misalignedJSDocComment" ,
125
+ node : c ,
126
+ loc : {
127
+ start : {
128
+ line,
129
+ column : 0 ,
130
+ } ,
131
+ end : {
132
+ line,
133
+ column : actual - 1 ,
134
+ }
135
+ } ,
136
+ fix : ( fixer ) => {
137
+ if ( diff > 0 ) {
138
+ // Too many
139
+ const start = sourceCode . getIndexFromLoc ( { line, column : expected - 1 } ) ;
140
+ return fixer . removeRange ( [ start , start + diff ] ) ;
141
+ }
142
+ else {
143
+ // Too few
144
+ const start = sourceCode . getIndexFromLoc ( { line, column : 0 } ) ;
145
+ return fixer . insertTextAfterRange ( [ start , start ] , " " . repeat ( - diff ) ) ;
146
+ }
147
+ } ,
148
+ } ) ;
149
+ break ;
150
+ }
151
+ }
152
+ }
153
+ } ;
154
+
89
155
return {
90
- ClassDeclaration : checkJSDocFormat ,
91
- FunctionDeclaration : checkJSDocFormat ,
92
- TSEnumDeclaration : checkJSDocFormat ,
93
- TSModuleDeclaration : checkJSDocFormat ,
94
- VariableDeclaration : checkJSDocFormat ,
95
- TSInterfaceDeclaration : checkJSDocFormat ,
96
- TSTypeAliasDeclaration : checkJSDocFormat ,
97
- TSCallSignatureDeclaration : checkJSDocFormat ,
98
- ExportAllDeclaration : checkJSDocFormat ,
99
- ExportNamedDeclaration : checkJSDocFormat ,
100
- TSImportEqualsDeclaration : checkJSDocFormat ,
101
- TSNamespaceExportDeclaration : checkJSDocFormat ,
102
- TSConstructSignatureDeclaration : checkJSDocFormat ,
103
- ExportDefaultDeclaration : checkJSDocFormat ,
104
- TSPropertySignature : checkJSDocFormat ,
105
- TSIndexSignature : checkJSDocFormat ,
106
- TSMethodSignature : checkJSDocFormat ,
107
- TSParameterProperty : checkJSDocFormat ,
156
+ Program : checkProgram ,
157
+ ClassDeclaration : checkDeclaration ,
158
+ FunctionDeclaration : checkDeclaration ,
159
+ TSEnumDeclaration : checkDeclaration ,
160
+ TSModuleDeclaration : checkDeclaration ,
161
+ VariableDeclaration : checkDeclaration ,
162
+ TSInterfaceDeclaration : checkDeclaration ,
163
+ TSTypeAliasDeclaration : checkDeclaration ,
164
+ TSCallSignatureDeclaration : checkDeclaration ,
165
+ ExportAllDeclaration : checkDeclaration ,
166
+ ExportNamedDeclaration : checkDeclaration ,
167
+ TSImportEqualsDeclaration : checkDeclaration ,
168
+ TSNamespaceExportDeclaration : checkDeclaration ,
169
+ TSConstructSignatureDeclaration : checkDeclaration ,
170
+ ExportDefaultDeclaration : checkDeclaration ,
171
+ TSPropertySignature : checkDeclaration ,
172
+ TSIndexSignature : checkDeclaration ,
173
+ TSMethodSignature : checkDeclaration ,
174
+ TSParameterProperty : checkDeclaration ,
108
175
} ;
109
176
} ,
110
177
} ) ;
0 commit comments