Skip to content

Commit 852f2d9

Browse files
committed
Merge pull request microsoft#516 from Microsoft/pinnedComments
Emit pinned or ///<reference> tag comments for signatures, ambient declaraitons and interfaces
2 parents 00a37a6 + c4fdcca commit 852f2d9

29 files changed

+451
-23
lines changed

src/compiler/emitter.ts

+68-9
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);
@@ -1666,6 +1682,10 @@ module ts {
16661682
}
16671683
}
16681684

1685+
function emitInterfaceDeclaration(node: InterfaceDeclaration) {
1686+
emitPinnedOrTripleSlashComments(node);
1687+
}
1688+
16691689
function emitEnumDeclaration(node: EnumDeclaration) {
16701690
emitLeadingComments(node);
16711691
if (!(node.flags & NodeFlags.Export)) {
@@ -1741,7 +1761,10 @@ module ts {
17411761
}
17421762

17431763
function emitModuleDeclaration(node: ModuleDeclaration) {
1744-
if (!isInstantiated(node)) return;
1764+
if (!isInstantiated(node)) {
1765+
return emitPinnedOrTripleSlashComments(node);
1766+
}
1767+
17451768
emitLeadingComments(node);
17461769
if (!(node.flags & NodeFlags.Export)) {
17471770
emitStart(node);
@@ -1969,7 +1992,14 @@ module ts {
19691992
}
19701993

19711994
function emitNode(node: Node) {
1972-
if (!node || node.flags & NodeFlags.Ambient) return;
1995+
if (!node) {
1996+
return;
1997+
}
1998+
1999+
if (node.flags & NodeFlags.Ambient) {
2000+
return emitPinnedOrTripleSlashComments(node);
2001+
}
2002+
19732003
switch (node.kind) {
19742004
case SyntaxKind.Identifier:
19752005
return emitIdentifier(<Identifier>node);
@@ -2073,6 +2103,8 @@ module ts {
20732103
return emitVariableDeclaration(<VariableDeclaration>node);
20742104
case SyntaxKind.ClassDeclaration:
20752105
return emitClassDeclaration(<ClassDeclaration>node);
2106+
case SyntaxKind.InterfaceDeclaration:
2107+
return emitInterfaceDeclaration(<InterfaceDeclaration>node);
20762108
case SyntaxKind.EnumDeclaration:
20772109
return emitEnumDeclaration(<EnumDeclaration>node);
20782110
case SyntaxKind.ModuleDeclaration:
@@ -2101,7 +2133,7 @@ module ts {
21012133
return leadingComments;
21022134
}
21032135

2104-
function emitLeadingDeclarationComments(node: Node) {
2136+
function getLeadingCommentsToEmit(node: Node) {
21052137
// Emit the leading comments only if the parent's pos doesnt match because parent should take care of emitting these comments
21062138
if (node.parent.kind === SyntaxKind.SourceFile || node.pos !== node.parent.pos) {
21072139
var leadingComments: Comment[];
@@ -2113,12 +2145,17 @@ module ts {
21132145
// get the leading comments from the node
21142146
leadingComments = getLeadingCommentsOfNode(node, currentSourceFile);
21152147
}
2116-
emitNewLineBeforeLeadingComments(node, leadingComments, writer);
2117-
// Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
2118-
emitComments(leadingComments, /*trailingSeparator*/ true, writer, writeComment);
2148+
return leadingComments;
21192149
}
21202150
}
21212151

2152+
function emitLeadingDeclarationComments(node: Node) {
2153+
var leadingComments = getLeadingCommentsToEmit(node);
2154+
emitNewLineBeforeLeadingComments(node, leadingComments, writer);
2155+
// Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
2156+
emitComments(leadingComments, /*trailingSeparator*/ true, writer, writeComment);
2157+
}
2158+
21222159
function emitTrailingDeclarationComments(node: Node) {
21232160
// Emit the trailing comments only if the parent's end doesnt match
21242161
if (node.parent.kind === SyntaxKind.SourceFile || node.end !== node.parent.end) {
@@ -2166,7 +2203,7 @@ module ts {
21662203
lastComment = comment;
21672204
});
21682205

2169-
if (detachedComments && detachedComments.length) {
2206+
if (detachedComments.length) {
21702207
// All comments look like they could have been part of the copyright header. Make
21712208
// sure there is at least one blank line between it and the node. If not, it's not
21722209
// a copyright header.
@@ -2188,6 +2225,28 @@ module ts {
21882225
}
21892226
}
21902227

2228+
function emitPinnedOrTripleSlashCommentsOfNode(node: Node) {
2229+
var pinnedComments = ts.filter(getLeadingCommentsToEmit(node), isPinnedOrTripleSlashComment);
2230+
2231+
function isPinnedOrTripleSlashComment(comment: Comment) {
2232+
if (currentSourceFile.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk) {
2233+
return currentSourceFile.text.charCodeAt(comment.pos + 2) === CharacterCodes.exclamation;
2234+
}
2235+
// Verify this is /// comment, but do the regexp match only when we first can find /// in the comment text
2236+
// so that we dont end up computing comment string and doing match for all // comments
2237+
else if (currentSourceFile.text.charCodeAt(comment.pos + 1) === CharacterCodes.slash &&
2238+
comment.pos + 2 < comment.end &&
2239+
currentSourceFile.text.charCodeAt(comment.pos + 2) === CharacterCodes.slash &&
2240+
currentSourceFile.text.substring(comment.pos, comment.end).match(fullTripleSlashReferencePathRegEx)) {
2241+
return true;
2242+
}
2243+
}
2244+
2245+
emitNewLineBeforeLeadingComments(node, pinnedComments, writer);
2246+
// Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
2247+
emitComments(pinnedComments, /*trailingSeparator*/ true, writer, writeComment);
2248+
}
2249+
21912250
if (compilerOptions.sourceMap) {
21922251
initializeEmitterWithSourceMaps();
21932252
}

src/compiler/parser.ts

+3-2
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;

tests/baselines/reference/checkInterfaceBases.js

+1
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ interface Third extends JQueryEventObjectTest, SecondEvent {}
1616

1717

1818
//// [app.js]
19+
///<reference path='jquery.d.ts' />
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
1-
//// [commentOnAmbientClass1.ts]
1+
//// [tests/cases/compiler/commentOnAmbientClass1.ts] ////
2+
3+
//// [a.ts]
24
/*! Keep this pinned comment */
35
declare class C {
46
}
57

68
// Don't keep this comment.
79
declare class D {
10+
}
11+
12+
//// [b.ts]
13+
///<reference path="a.ts"/>
14+
declare class E extends C {
815
}
916

10-
//// [commentOnAmbientClass1.js]
17+
//// [a.js]
18+
/*! Keep this pinned comment */
19+
//// [b.js]
20+
///<reference path="a.ts"/>

tests/baselines/reference/commentOnAmbientClass1.types

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
=== tests/cases/compiler/commentOnAmbientClass1.ts ===
1+
=== tests/cases/compiler/b.ts ===
2+
///<reference path="a.ts"/>
3+
declare class E extends C {
4+
>E : E
5+
>C : C
6+
}
7+
=== tests/cases/compiler/a.ts ===
28
/*! Keep this pinned comment */
39
declare class C {
410
>C : C
@@ -8,3 +14,4 @@ declare class C {
814
declare class D {
915
>D : D
1016
}
17+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//// [tests/cases/compiler/commentOnAmbientEnum.ts] ////
2+
3+
//// [a.ts]
4+
/*! Keep this pinned comment */
5+
declare enum C {
6+
a,
7+
b,
8+
c
9+
}
10+
11+
// Don't keep this comment.
12+
declare enum D {
13+
}
14+
15+
//// [b.ts]
16+
///<reference path="a.ts"/>
17+
declare enum E {
18+
}
19+
20+
//// [a.js]
21+
/*! Keep this pinned comment */
22+
//// [b.js]
23+
///<reference path="a.ts"/>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
=== tests/cases/compiler/b.ts ===
2+
///<reference path="a.ts"/>
3+
declare enum E {
4+
>E : E
5+
}
6+
=== tests/cases/compiler/a.ts ===
7+
/*! Keep this pinned comment */
8+
declare enum C {
9+
>C : C
10+
11+
a,
12+
>a : C
13+
14+
b,
15+
>b : C
16+
17+
c
18+
>c : C
19+
}
20+
21+
// Don't keep this comment.
22+
declare enum D {
23+
>D : D
24+
}
25+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//// [tests/cases/compiler/commentOnAmbientModule.ts] ////
2+
3+
//// [a.ts]
4+
/*! Keep this pinned comment */
5+
declare module C {
6+
function foo();
7+
}
8+
9+
// Don't keep this comment.
10+
declare module D {
11+
class bar { }
12+
}
13+
14+
//// [b.ts]
15+
///<reference path="a.ts"/>
16+
declare module E {
17+
class foobar extends D.bar {
18+
foo();
19+
}
20+
}
21+
22+
//// [a.js]
23+
/*! Keep this pinned comment */
24+
//// [b.js]
25+
///<reference path="a.ts"/>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
=== tests/cases/compiler/b.ts ===
2+
///<reference path="a.ts"/>
3+
declare module E {
4+
>E : typeof E
5+
6+
class foobar extends D.bar {
7+
>foobar : foobar
8+
>D : D
9+
>bar : bar
10+
11+
foo();
12+
>foo : () => any
13+
}
14+
}
15+
=== tests/cases/compiler/a.ts ===
16+
/*! Keep this pinned comment */
17+
declare module C {
18+
>C : typeof C
19+
20+
function foo();
21+
>foo : () => any
22+
}
23+
24+
// Don't keep this comment.
25+
declare module D {
26+
>D : typeof D
27+
28+
class bar { }
29+
>bar : bar
30+
}
31+

tests/baselines/reference/commentOnAmbientVariable1.js

+1
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ declare var v: number;
66
declare var y: number;
77

88
//// [commentOnAmbientVariable1.js]
9+
/*! Keep this pinned comment */

tests/baselines/reference/commentOnAmbientVariable2.js

+1
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ x = 2;
1111
//// [commentOnAmbientVariable2_1.js]
1212
var y = 1;
1313
//// [commentOnAmbientVariable2_2.js]
14+
/// <reference path='commentOnAmbientVariable2_1.ts'/>
1415
x = 2;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//// [tests/cases/compiler/commentOnAmbientfunction.ts] ////
2+
3+
//// [a.ts]
4+
/*! Keep this pinned comment */
5+
declare function foo();
6+
7+
// Don't keep this comment.
8+
declare function bar();
9+
10+
//// [b.ts]
11+
///<reference path="a.ts"/>
12+
declare function foobar(a: typeof foo): typeof bar;
13+
14+
//// [a.js]
15+
/*! Keep this pinned comment */
16+
//// [b.js]
17+
///<reference path="a.ts"/>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
=== tests/cases/compiler/b.ts ===
2+
///<reference path="a.ts"/>
3+
declare function foobar(a: typeof foo): typeof bar;
4+
>foobar : (a: () => any) => () => any
5+
>a : () => any
6+
>foo : () => any
7+
>bar : () => any
8+
9+
=== tests/cases/compiler/a.ts ===
10+
/*! Keep this pinned comment */
11+
declare function foo();
12+
>foo : () => any
13+
14+
// Don't keep this comment.
15+
declare function bar();
16+
>bar : () => any
17+

0 commit comments

Comments
 (0)