@@ -12,7 +12,6 @@ import * as tsickle from './tsickle';
12
12
/**
13
13
* Adjusts the given CustomTransformers with additional transformers
14
14
* to fix bugs in TypeScript.
15
- * @param given A
16
15
*/
17
16
export function createCustomTransformers ( given : ts . CustomTransformers ) : ts . CustomTransformers {
18
17
if ( ! given . after && ! given . before ) {
@@ -51,7 +50,7 @@ function assertFileContext(context: TransformationContext, sourceFile: ts.Source
51
50
}
52
51
53
52
/**
54
- * And extended version of the TransformationContext that stores the FileContext as well.
53
+ * An extended version of the TransformationContext that stores the FileContext as well.
55
54
*/
56
55
interface TransformationContext extends ts . TransformationContext {
57
56
fileContext ?: FileContext ;
@@ -74,6 +73,8 @@ class FileContext {
74
73
* Transform that needs to be executed right before TypeScript's transform.
75
74
*
76
75
* This prepares the node tree to workaround some bugs in the TypeScript emitter.
76
+ * TODO(tbosch): file issues with TypeScript, tracked in
77
+ * https://github.com/angular/tsickle/issues/528.
77
78
*/
78
79
function preTypeScriptTransform ( context : ts . TransformationContext ) {
79
80
return ( sourceFile : ts . SourceFile ) => {
@@ -178,7 +179,7 @@ function postTypescriptTransform(context: ts.TransformationContext) {
178
179
} else if (
179
180
parent3 && parent3 . kind === ts . SyntaxKind . VariableStatement &&
180
181
tsickle . hasModifierFlag ( parent3 , ts . ModifierFlags . Export ) ) {
181
- // TypeScript ignore synthetic comments on exported variables.
182
+ // TypeScript ignores synthetic comments on exported variables.
182
183
// find the parent ExpressionStatement like exports.foo = ...
183
184
const expressionStmt =
184
185
lastNodeWith ( nodePath , ( node ) => node . kind === ts . SyntaxKind . ExpressionStatement ) ;
@@ -188,7 +189,7 @@ function postTypescriptTransform(context: ts.TransformationContext) {
188
189
}
189
190
}
190
191
}
191
- // TypeScript ignore synthetic comments on reexport / import statements.
192
+ // TypeScript ignores synthetic comments on reexport / import statements.
192
193
const moduleName = extractModuleNameFromRequireVariableStatement ( node ) ;
193
194
if ( moduleName && fileContext . importOrReexportDeclarations ) {
194
195
const index = importOrReexportsCount ++ ;
@@ -240,8 +241,13 @@ function lastNodeWith(nodes: ts.Node[], predicate: (node: ts.Node) => boolean):
240
241
}
241
242
242
243
/**
243
- * Synthesizes the comments before and after a node
244
- * befor calling a callback.
244
+ * Convert comment text ranges before and after a node
245
+ * into ts.SynthesizedComments for the node and prevent the
246
+ * comment text ranges to be emitted, to allow
247
+ * changing these comments.
248
+ *
249
+ * This function takes a visitor to be able to do some
250
+ * state management after the caller is done changing a node.
245
251
*/
246
252
export function visitNodeWithSynthesizedComments < T extends ts . Node > (
247
253
context : ts . TransformationContext , sourceFile : ts . SourceFile , node : T ,
@@ -288,7 +294,8 @@ function resetNodeTextRangeToPreventDuplicateComments<T extends ts.Node>(node: T
288
294
if ( node . kind === ts . SyntaxKind . PropertyDeclaration ) {
289
295
allowTextRange = false ;
290
296
const pd = node as ts . Node as ts . PropertyDeclaration ;
291
- // TODO(tbosch): Using pd.initializer! as the typescript typings for intializer are incorrect.
297
+ // TODO(tbosch): Using pd.initializer! as the typescript typings for intializer are incorrect,
298
+ // tracked in https://github.com/angular/tsickle/issues/528.
292
299
node = ts . updateProperty (
293
300
pd , pd . decorators , pd . modifiers , resetTextRange ( pd . name ) as ts . PropertyName , pd . type ,
294
301
pd . initializer ! ) as ts . Node as T ;
@@ -311,6 +318,13 @@ function resetNodeTextRangeToPreventDuplicateComments<T extends ts.Node>(node: T
311
318
}
312
319
}
313
320
321
+ /**
322
+ * Reads in the leading comment text ranges of the given node,
323
+ * converts them into `ts.SyntheticComment`s and stores them on the node.
324
+ *
325
+ * @param lastCommentEnd The end of the last comment
326
+ * @return The end of the last found comment, -1 if no comment was found.
327
+ */
314
328
function synthesizeLeadingComments (
315
329
sourceFile : ts . SourceFile , node : ts . Node , lastCommentEnd : number ) : number {
316
330
const parent = node . parent ;
@@ -329,6 +343,12 @@ function synthesizeLeadingComments(
329
343
return - 1 ;
330
344
}
331
345
346
+ /**
347
+ * Reads in the trailing comment text ranges of the given node,
348
+ * converts them into `ts.SyntheticComment`s and stores them on the node.
349
+ *
350
+ * @return The end of the last found comment, -1 if no comment was found.
351
+ */
332
352
function synthesizeTrailingComments ( sourceFile : ts . SourceFile , node : ts . Node ) : number {
333
353
const parent = node . parent ;
334
354
const sharesEndWithParent = parent && parent . kind !== ts . SyntaxKind . Block &&
@@ -344,6 +364,16 @@ function synthesizeTrailingComments(sourceFile: ts.SourceFile, node: ts.Node): n
344
364
return - 1 ;
345
365
}
346
366
367
+ /**
368
+ * Convert leading/trailing detached comment ranges of statement arrays
369
+ * (e.g. the statements of a ts.SourceFile or ts.Block) into
370
+ * `ts.NonEmittedStatement`s with `ts.SynthesizedComment`s and
371
+ * prepends / appends them to the given statement array.
372
+ * This is needed to allow changing these comments.
373
+ *
374
+ * This function takes a visitor to be able to do some
375
+ * state management after the caller is done changing a node.
376
+ */
347
377
function visitNodeStatementsWithSynthesizedComments < T extends ts . Node > (
348
378
context : ts . TransformationContext , sourceFile : ts . SourceFile , node : T ,
349
379
statements : ts . NodeArray < ts . Statement > ,
@@ -371,14 +401,22 @@ function visitNodeStatementsWithSynthesizedComments<T extends ts.Node>(
371
401
return visitor ( node , statements ) ;
372
402
}
373
403
404
+ /**
405
+ * Convert leading detached comment ranges of statement arrays
406
+ * (e.g. the statements of a ts.SourceFile or ts.Block) into a
407
+ * `ts.NonEmittedStatement` with `ts.SynthesizedComment`s.
408
+ *
409
+ * A Detached leading comment is the first comment in a SourceFile / Block
410
+ * that is separated with a newline from the first statement.
411
+ */
374
412
function synthesizeDetachedLeadingComments (
375
413
sourceFile : ts . SourceFile , node : ts . Node , statements : ts . NodeArray < ts . Statement > ) :
376
414
{ commentStmt : ts . Statement | null , lastCommentEnd : number } {
377
415
let triviaEnd = statements . end ;
378
416
if ( statements . length ) {
379
417
triviaEnd = statements [ statements . length - 1 ] . getStart ( ) ;
380
418
}
381
- const detachedComments = getDetachedStartingComments ( sourceFile , statements . pos , triviaEnd ) ;
419
+ const detachedComments = getDetachedLeadingCommentRanges ( sourceFile , statements . pos , triviaEnd ) ;
382
420
if ( ! detachedComments . length ) {
383
421
return { commentStmt : null , lastCommentEnd : - 1 } ;
384
422
}
@@ -390,6 +428,14 @@ function synthesizeDetachedLeadingComments(
390
428
return { commentStmt, lastCommentEnd} ;
391
429
}
392
430
431
+ /**
432
+ * Convert trailing detached comment ranges of statement arrays
433
+ * (e.g. the statements of a ts.SourceFile or ts.Block) into a
434
+ * `ts.NonEmittedStatement` with `ts.SynthesizedComment`s.
435
+ *
436
+ * A Detached trailing comment are all comments after the first newline
437
+ * the follows the last statement in a SourceFile / Block.
438
+ */
393
439
function synthesizeDetachedTrailingComments (
394
440
sourceFile : ts . SourceFile , node : ts . Node , statements : ts . NodeArray < ts . Statement > ) :
395
441
{ commentStmt : ts . Statement | null , lastCommentEnd : number } {
@@ -413,8 +459,14 @@ function synthesizeDetachedTrailingComments(
413
459
return { commentStmt, lastCommentEnd} ;
414
460
}
415
461
416
- // Adapted from compiler/comments.ts in TypeScript
417
- function getDetachedStartingComments (
462
+ /**
463
+ * Calculates the the detached leading comment ranges in an area of a SourceFile.
464
+ * @param sourceFile The source file
465
+ * @param start Where to start scanning
466
+ * @param end Where to end scanning
467
+ */
468
+ // Note: This code is based on compiler/comments.ts in TypeScript
469
+ function getDetachedLeadingCommentRanges (
418
470
sourceFile : ts . SourceFile , start : number , end : number ) : ts . CommentRange [ ] {
419
471
const leadingComments = getAllLeadingCommentRanges ( sourceFile , start , end ) ;
420
472
if ( ! leadingComments || ! leadingComments . length ) {
@@ -459,8 +511,13 @@ function getLineOfPos(sourceFile: ts.SourceFile, pos: number): number {
459
511
return ts . getLineAndCharacterOfPosition ( sourceFile , pos ) . line ;
460
512
}
461
513
462
-
463
- function synthesizeCommentRanges ( sourceFile : ts . SourceFile , parsedComments : ts . CommentRange [ ] ) {
514
+ /**
515
+ * Converts `ts.CommentRange`s into `ts.SynthesizedComment`s
516
+ * @param sourceFile
517
+ * @param parsedComments
518
+ */
519
+ function synthesizeCommentRanges (
520
+ sourceFile : ts . SourceFile , parsedComments : ts . CommentRange [ ] ) : ts . SynthesizedComment [ ] {
464
521
const synthesizedComments : ts . SynthesizedComment [ ] = [ ] ;
465
522
parsedComments . forEach ( ( { kind, pos, end, hasTrailingNewLine} , commentIdx ) => {
466
523
let commentText = sourceFile . text . substring ( pos , end ) . trim ( ) ;
@@ -478,13 +535,25 @@ function synthesizeCommentRanges(sourceFile: ts.SourceFile, parsedComments: ts.C
478
535
return synthesizedComments ;
479
536
}
480
537
538
+ /**
539
+ * Creates a non emitted statement that can be used to store synthesized comments.
540
+ */
481
541
function createNotEmittedStatement ( sourceFile : ts . SourceFile ) {
482
542
const stmt = ts . createNotEmittedStatement ( sourceFile ) ;
483
543
ts . setOriginalNode ( stmt , undefined ) ;
484
544
ts . setTextRange ( stmt , { pos : 0 , end : 0 } ) ;
485
545
return stmt ;
486
546
}
487
547
548
+ /**
549
+ * Returns the leading comment ranges in the source file that start at the given position.
550
+ * This is the same as `ts.getLeadingCommentRanges`, except that it does not skip
551
+ * comments before the first newline in the range.
552
+ *
553
+ * @param sourceFile
554
+ * @param start Where to start scanning
555
+ * @param end Where to end scanning
556
+ */
488
557
function getAllLeadingCommentRanges (
489
558
sourceFile : ts . SourceFile , start : number , end : number ) : ts . CommentRange [ ] {
490
559
// exeute ts.getLeadingCommentRanges with pos = 0 so that it does not skip
@@ -498,6 +567,15 @@ function getAllLeadingCommentRanges(
498
567
} ) ) ;
499
568
}
500
569
570
+ /**
571
+ * This is a version of `ts.updateSourceFileNode` that prevents some
572
+ * bugs in TypeScript.
573
+ * TODO(tbosch): file an issue with TypeScript, tracked in
574
+ * https://github.com/angular/tsickle/issues/528.
575
+ *
576
+ * @param sf
577
+ * @param statements
578
+ */
501
579
export function updateSourceFileNode (
502
580
sf : ts . SourceFile , statements : ts . NodeArray < ts . Statement > ) : ts . SourceFile {
503
581
if ( statements === sf . statements ) {
@@ -522,6 +600,12 @@ export function getMutableClone<T extends ts.Node>(node: T): T {
522
600
return clone ;
523
601
}
524
602
603
+ /**
604
+ * This is a version of `ts.visitEachChild` that does not visit children of types
605
+ * to prevent errors from TypeScript.
606
+ * TODO(tbosch): file an issue with TypeScript, tracked in
607
+ * https://github.com/angular/tsickle/issues/528.
608
+ */
525
609
export function visitEachChild < T extends ts . Node > (
526
610
node : T , visitor : ts . Visitor , context : ts . TransformationContext ) : T {
527
611
// Don't visit children of types,
0 commit comments