Skip to content

Commit 85b892f

Browse files
committed
Emit pinned/tripleslash reference comments of signatures
Fixes #501
1 parent e6cd3e1 commit 85b892f

File tree

5 files changed

+168
-12
lines changed

5 files changed

+168
-12
lines changed

src/compiler/emitter.ts

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,9 @@ module ts {
336336
/** Emit detached comments of the node */
337337
var emitDetachedComments = compilerOptions.removeComments ? (node: TextRange) => { } : emitDetachedCommentsAtPosition;
338338

339+
/** Emits /// or pinned which is comment starting with /*! comments */
340+
var emitPinnedOrTripleSlashComments = compilerOptions.removeComments ? (node: Node) => { } : emitPinnedOrTripleSlashCommentsOfNode;
341+
339342
var writeComment = writeCommentRange;
340343

341344
/** Emit a node */
@@ -1318,7 +1321,10 @@ module ts {
13181321
}
13191322

13201323
function emitFunctionDeclaration(node: FunctionDeclaration) {
1321-
if (!node.body) return;
1324+
if (!node.body) {
1325+
return emitPinnedOrTripleSlashComments(node);
1326+
}
1327+
13221328
if (node.kind !== SyntaxKind.Method) {
13231329
// Methods will emit the comments as part of emitting method declaration
13241330
emitLeadingComments(node);
@@ -1488,7 +1494,10 @@ module ts {
14881494
function emitMemberFunctions(node: ClassDeclaration) {
14891495
forEach(node.members, member => {
14901496
if (member.kind === SyntaxKind.Method) {
1491-
if (!(<MethodDeclaration>member).body) return;
1497+
if (!(<MethodDeclaration>member).body) {
1498+
return emitPinnedOrTripleSlashComments(member);
1499+
}
1500+
14921501
writeLine();
14931502
emitLeadingComments(member);
14941503
emitStart(member);
@@ -1611,6 +1620,13 @@ module ts {
16111620
emitTrailingComments(node);
16121621

16131622
function emitConstructorOfClass() {
1623+
// Emit the constructor overload pinned comments
1624+
forEach(node.members, member => {
1625+
if (member.kind === SyntaxKind.Constructor && !(<ConstructorDeclaration>member).body) {
1626+
emitPinnedOrTripleSlashComments(member);
1627+
}
1628+
});
1629+
16141630
var ctor = getFirstConstructorWithBody(node);
16151631
if (ctor) {
16161632
emitLeadingComments(ctor);
@@ -2101,7 +2117,7 @@ module ts {
21012117
return leadingComments;
21022118
}
21032119

2104-
function emitLeadingDeclarationComments(node: Node) {
2120+
function getLeadingCommentsToEmit(node: Node) {
21052121
// Emit the leading comments only if the parent's pos doesnt match because parent should take care of emitting these comments
21062122
if (node.parent.kind === SyntaxKind.SourceFile || node.pos !== node.parent.pos) {
21072123
var leadingComments: Comment[];
@@ -2113,12 +2129,17 @@ module ts {
21132129
// get the leading comments from the node
21142130
leadingComments = getLeadingCommentsOfNode(node, currentSourceFile);
21152131
}
2116-
emitNewLineBeforeLeadingComments(node, leadingComments, writer);
2117-
// Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
2118-
emitComments(leadingComments, /*trailingSeparator*/ true, writer, writeComment);
2132+
return leadingComments;
21192133
}
21202134
}
21212135

2136+
function emitLeadingDeclarationComments(node: Node) {
2137+
var leadingComments = getLeadingCommentsToEmit(node);
2138+
emitNewLineBeforeLeadingComments(node, leadingComments, writer);
2139+
// Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
2140+
emitComments(leadingComments, /*trailingSeparator*/ true, writer, writeComment);
2141+
}
2142+
21222143
function emitTrailingDeclarationComments(node: Node) {
21232144
// Emit the trailing comments only if the parent's end doesnt match
21242145
if (node.parent.kind === SyntaxKind.SourceFile || node.end !== node.parent.end) {
@@ -2166,7 +2187,7 @@ module ts {
21662187
lastComment = comment;
21672188
});
21682189

2169-
if (detachedComments && detachedComments.length) {
2190+
if (detachedComments.length) {
21702191
// All comments look like they could have been part of the copyright header. Make
21712192
// sure there is at least one blank line between it and the node. If not, it's not
21722193
// a copyright header.
@@ -2188,6 +2209,28 @@ module ts {
21882209
}
21892210
}
21902211

2212+
function emitPinnedOrTripleSlashCommentsOfNode(node: Node) {
2213+
var pinnedComments = ts.filter(getLeadingCommentsToEmit(node), isPinnedOrTripleSlashComment);
2214+
2215+
function isPinnedOrTripleSlashComment(comment: Comment) {
2216+
if (currentSourceFile.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk) {
2217+
return currentSourceFile.text.charCodeAt(comment.pos + 2) === CharacterCodes.exclamation;
2218+
}
2219+
// Verify this is /// comment, but do the regexp match only when we first can find /// in the comment text
2220+
// so that we dont end up computing comment string and doing match for all // comments
2221+
else if (currentSourceFile.text.charCodeAt(comment.pos + 1) === CharacterCodes.slash &&
2222+
comment.pos + 2 < comment.end &&
2223+
currentSourceFile.text.charCodeAt(comment.pos + 2) === CharacterCodes.slash &&
2224+
currentSourceFile.text.substring(comment.pos, comment.end).match(fullTripleSlashReferencePathRegEx)) {
2225+
return true;
2226+
}
2227+
}
2228+
2229+
emitNewLineBeforeLeadingComments(node, pinnedComments, writer);
2230+
// Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
2231+
emitComments(pinnedComments, /*trailingSeparator*/ true, writer, writeComment);
2232+
}
2233+
21912234
if (compilerOptions.sourceMap) {
21922235
initializeEmitterWithSourceMaps();
21932236
}

src/compiler/parser.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ module ts {
165165
}
166166
}
167167

168+
export var fullTripleSlashReferencePathRegEx = /^(\/\/\/\s*<reference\s+path\s*=\s*)('|")(.+?)\2.*?\/>/
169+
168170
// Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes
169171
// stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; otherwise,
170172
// embedded arrays are flattened and the 'cbNode' callback is invoked for each element. If a callback returns
@@ -3506,8 +3508,7 @@ module ts {
35063508
file.hasNoDefaultLib = true;
35073509
}
35083510
else {
3509-
var fullReferenceRegEx = /^(\/\/\/\s*<reference\s+path\s*=\s*)('|")(.+?)\2.*?\/>/;
3510-
var matchResult = fullReferenceRegEx.exec(comment);
3511+
var matchResult = fullTripleSlashReferencePathRegEx.exec(comment);
35113512
if (!matchResult) {
35123513
var start = range.pos;
35133514
var length = range.end - start;
Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,51 @@
1-
//// [commentOnSignature1.ts]
1+
//// [tests/cases/compiler/commentOnSignature1.ts] ////
2+
3+
//// [a.ts]
24
/*! Keep this pinned comment */
35
function foo(n: number): void;
46
// Don't keep this comment.
57
function foo(s: string): void;
68
function foo(a: any): void {
9+
}
10+
11+
class c {
12+
// dont keep this comment
13+
constructor(a: string);
14+
/*! keep this pinned comment */
15+
constructor(a: number);
16+
constructor(a: any) {
17+
}
18+
19+
// dont keep this comment
20+
foo(a: string);
21+
/*! keep this pinned comment */
22+
foo(a: number);
23+
foo(a: any) {
24+
}
25+
}
26+
27+
//// [b.ts]
28+
///<reference path='a.ts'/>
29+
function foo2(n: number): void;
30+
// Don't keep this comment.
31+
function foo2(s: string): void;
32+
function foo2(a: any): void {
733
}
834

9-
//// [commentOnSignature1.js]
35+
//// [a.js]
36+
/*! Keep this pinned comment */
1037
function foo(a) {
1138
}
39+
var c = (function () {
40+
/*! keep this pinned comment */
41+
function c(a) {
42+
}
43+
/*! keep this pinned comment */
44+
c.prototype.foo = function (a) {
45+
};
46+
return c;
47+
})();
48+
//// [b.js]
49+
///<reference path='a.ts'/>
50+
function foo2(a) {
51+
}

tests/baselines/reference/commentOnSignature1.types

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,19 @@
1-
=== tests/cases/compiler/commentOnSignature1.ts ===
1+
=== tests/cases/compiler/b.ts ===
2+
///<reference path='a.ts'/>
3+
function foo2(n: number): void;
4+
>foo2 : { (n: number): void; (s: string): void; }
5+
>n : number
6+
7+
// Don't keep this comment.
8+
function foo2(s: string): void;
9+
>foo2 : { (n: number): void; (s: string): void; }
10+
>s : string
11+
12+
function foo2(a: any): void {
13+
>foo2 : { (n: number): void; (s: string): void; }
14+
>a : any
15+
}
16+
=== tests/cases/compiler/a.ts ===
217
/*! Keep this pinned comment */
318
function foo(n: number): void;
419
>foo : { (n: number): void; (s: string): void; }
@@ -13,3 +28,35 @@ function foo(a: any): void {
1328
>foo : { (n: number): void; (s: string): void; }
1429
>a : any
1530
}
31+
32+
class c {
33+
>c : c
34+
35+
// dont keep this comment
36+
constructor(a: string);
37+
>a : string
38+
39+
/*! keep this pinned comment */
40+
constructor(a: number);
41+
>a : number
42+
43+
constructor(a: any) {
44+
>a : any
45+
}
46+
47+
// dont keep this comment
48+
foo(a: string);
49+
>foo : { (a: string): any; (a: number): any; }
50+
>a : string
51+
52+
/*! keep this pinned comment */
53+
foo(a: number);
54+
>foo : { (a: string): any; (a: number): any; }
55+
>a : number
56+
57+
foo(a: any) {
58+
>foo : { (a: string): any; (a: number): any; }
59+
>a : any
60+
}
61+
}
62+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,31 @@
1+
// @filename: a.ts
12
/*! Keep this pinned comment */
23
function foo(n: number): void;
34
// Don't keep this comment.
45
function foo(s: string): void;
56
function foo(a: any): void {
7+
}
8+
9+
class c {
10+
// dont keep this comment
11+
constructor(a: string);
12+
/*! keep this pinned comment */
13+
constructor(a: number);
14+
constructor(a: any) {
15+
}
16+
17+
// dont keep this comment
18+
foo(a: string);
19+
/*! keep this pinned comment */
20+
foo(a: number);
21+
foo(a: any) {
22+
}
23+
}
24+
25+
//@filename:b.ts
26+
///<reference path='a.ts'/>
27+
function foo2(n: number): void;
28+
// Don't keep this comment.
29+
function foo2(s: string): void;
30+
function foo2(a: any): void {
631
}

0 commit comments

Comments
 (0)