@@ -10,7 +10,7 @@ import * as ts from 'typescript';
1010
1111import * as jsdoc from './jsdoc' ;
1212import * as path from './path' ;
13- import { createNotEmittedStatement , reportDiagnostic , synthesizeCommentRanges , updateSourceFileNode } from './transformer_util' ;
13+ import { reportDiagnostic , synthesizeCommentRanges , updateSourceFileNode } from './transformer_util' ;
1414
1515/**
1616 * A set of JSDoc tags that mark a comment as a fileoverview comment. These are
@@ -65,6 +65,9 @@ function augmentFileoverviewComments(
6565 // * Suppress uselessCode. We emit an "if (false)" around type
6666 // declarations, which is flagged as unused code unless we suppress it.
6767 'uselessCode' ,
68+ // suspiciousCode errors flag patterns that are suspicious if human-written
69+ // but not inherently wrong. See also b/323580655.
70+ 'suspiciousCode' ,
6871 // * Suppress some checks for user errors that TS already checks.
6972 'missingReturn' ,
7073 'unusedPrivateMembers' ,
@@ -152,35 +155,34 @@ export function transformFileoverviewCommentFactory(
152155 // they do not get lost later on.
153156 const synthesizedComments =
154157 jsdoc . synthesizeLeadingComments ( firstStatement ) ;
155- const notEmitted = ts . factory . createNotEmittedStatement ( sourceFile ) ;
156158 // Modify the comments on the firstStatement in place by removing the
157159 // file-level comments.
158160 fileComments = synthesizedComments . splice ( 0 , i + 1 ) ;
159- // Move the fileComments onto notEmitted.
160- ts . setSyntheticLeadingComments ( notEmitted , fileComments ) ;
161- sourceFile =
162- updateSourceFileNode ( sourceFile , ts . factory . createNodeArray ( [
163- notEmitted , firstStatement , ...sourceFile . statements . slice ( 1 )
164- ] ) ) ;
165161 break ;
166162 }
163+ }
167164
168-
169- // Now walk every top level statement and escape/drop any @fileoverview
170- // comments found. Closure ignores all @fileoverview comments but the
171- // last, so tsickle must make sure not to emit duplicated ones.
172- for ( let i = 0 ; i < sourceFile . statements . length ; i ++ ) {
173- const stmt = sourceFile . statements [ i ] ;
174- // Accept the NotEmittedStatement inserted above.
175- if ( i === 0 && stmt . kind === ts . SyntaxKind . NotEmittedStatement ) {
176- continue ;
177- }
178- const comments = jsdoc . synthesizeLeadingComments ( stmt ) ;
179- checkNoFileoverviewComments (
180- stmt , comments ,
181- `file comments must be at the top of the file, ` +
182- `separated from the file body by an empty line.` ) ;
165+ // Move the fileComments onto notEmitted.
166+ const notEmitted = ts . factory . createNotEmittedStatement ( sourceFile ) ;
167+ ts . setSyntheticLeadingComments ( notEmitted , fileComments ) ;
168+ sourceFile = updateSourceFileNode (
169+ sourceFile ,
170+ ts . factory . createNodeArray ( [ notEmitted , ... sourceFile . statements ] ) ) ;
171+
172+ // Now walk every top level statement and escape/drop any @fileoverview
173+ // comments found. Closure ignores all @fileoverview comments but the
174+ // last, so tsickle must make sure not to emit duplicated ones.
175+ for ( let i = 0 ; i < sourceFile . statements . length ; i ++ ) {
176+ const stmt = sourceFile . statements [ i ] ;
177+ // Accept the NotEmittedStatement inserted above.
178+ if ( i === 0 && stmt . kind === ts . SyntaxKind . NotEmittedStatement ) {
179+ continue ;
183180 }
181+ const comments = jsdoc . synthesizeLeadingComments ( stmt ) ;
182+ checkNoFileoverviewComments (
183+ stmt , comments ,
184+ `file comments must be at the top of the file, ` +
185+ `separated from the file body by an empty line.` ) ;
184186 }
185187
186188 // Closure Compiler considers the *last* comment with @fileoverview (or
@@ -192,14 +194,17 @@ export function transformFileoverviewCommentFactory(
192194 let fileoverviewIdx = - 1 ;
193195 let tags : jsdoc . Tag [ ] = [ ] ;
194196 for ( let i = fileComments . length - 1 ; i >= 0 ; i -- ) {
195- const parse = jsdoc . parseContents ( fileComments [ i ] . text ) ;
196- if ( parse !== null &&
197- parse . tags . some ( t => FILEOVERVIEW_COMMENT_MARKERS . has ( t . tagName ) ) ) {
197+ const parsed = jsdoc . parse ( fileComments [ i ] ) ;
198+ if ( parsed !== null &&
199+ parsed . tags . some (
200+ t => FILEOVERVIEW_COMMENT_MARKERS . has ( t . tagName ) ) ) {
198201 fileoverviewIdx = i ;
199- tags = parse . tags ;
202+ tags = parsed . tags ;
200203 break ;
201204 }
202205 }
206+ const mutableJsDoc = new jsdoc . MutableJSDoc (
207+ notEmitted , fileComments , fileoverviewIdx , tags ) ;
203208
204209 if ( fileoverviewIdx !== - 1 ) {
205210 checkNoFileoverviewComments (
@@ -208,28 +213,11 @@ export function transformFileoverviewCommentFactory(
208213 `duplicate file level comment` ) ;
209214 }
210215
211- augmentFileoverviewComments ( options , sourceFile , tags , generateExtraSuppressions ) ;
212- const commentText = jsdoc . toStringWithoutStartEnd ( tags ) ;
213-
214- if ( fileoverviewIdx < 0 ) {
215- // No existing comment to merge with, just emit a new one.
216- return addNewFileoverviewComment ( sourceFile , commentText ) ;
217- }
216+ augmentFileoverviewComments (
217+ options , sourceFile , mutableJsDoc . tags , generateExtraSuppressions ) ;
218+ mutableJsDoc . updateComment ( ) ;
218219
219- fileComments [ fileoverviewIdx ] . text = commentText ;
220- // sf does not need to be updated, synthesized comments are mutable.
221220 return sourceFile ;
222221 } ;
223222 } ;
224223}
225-
226- function addNewFileoverviewComment (
227- sf : ts . SourceFile , commentText : string ) : ts . SourceFile {
228- let syntheticFirstStatement = createNotEmittedStatement ( sf ) ;
229- syntheticFirstStatement = ts . addSyntheticTrailingComment (
230- syntheticFirstStatement , ts . SyntaxKind . MultiLineCommentTrivia ,
231- commentText , true ) ;
232- return updateSourceFileNode (
233- sf ,
234- ts . factory . createNodeArray ( [ syntheticFirstStatement , ...sf . statements ] ) ) ;
235- }
0 commit comments