Merge pull request #516 from Microsoft/pinnedComments

Emit pinned or ///<reference> tag comments for signatures, ambient declaraitons and interfaces
This commit is contained in:
Sheetal Nandi 2014-08-28 10:51:29 -07:00
commit 852f2d935c
29 changed files with 451 additions and 23 deletions

View file

@ -336,6 +336,9 @@ module ts {
/** Emit detached comments of the node */
var emitDetachedComments = compilerOptions.removeComments ? (node: TextRange) => { } : emitDetachedCommentsAtPosition;
/** Emits /// or pinned which is comment starting with /*! comments */
var emitPinnedOrTripleSlashComments = compilerOptions.removeComments ? (node: Node) => { } : emitPinnedOrTripleSlashCommentsOfNode;
var writeComment = writeCommentRange;
/** Emit a node */
@ -1318,7 +1321,10 @@ module ts {
}
function emitFunctionDeclaration(node: FunctionDeclaration) {
if (!node.body) return;
if (!node.body) {
return emitPinnedOrTripleSlashComments(node);
}
if (node.kind !== SyntaxKind.Method) {
// Methods will emit the comments as part of emitting method declaration
emitLeadingComments(node);
@ -1488,7 +1494,10 @@ module ts {
function emitMemberFunctions(node: ClassDeclaration) {
forEach(node.members, member => {
if (member.kind === SyntaxKind.Method) {
if (!(<MethodDeclaration>member).body) return;
if (!(<MethodDeclaration>member).body) {
return emitPinnedOrTripleSlashComments(member);
}
writeLine();
emitLeadingComments(member);
emitStart(member);
@ -1611,6 +1620,13 @@ module ts {
emitTrailingComments(node);
function emitConstructorOfClass() {
// Emit the constructor overload pinned comments
forEach(node.members, member => {
if (member.kind === SyntaxKind.Constructor && !(<ConstructorDeclaration>member).body) {
emitPinnedOrTripleSlashComments(member);
}
});
var ctor = getFirstConstructorWithBody(node);
if (ctor) {
emitLeadingComments(ctor);
@ -1666,6 +1682,10 @@ module ts {
}
}
function emitInterfaceDeclaration(node: InterfaceDeclaration) {
emitPinnedOrTripleSlashComments(node);
}
function emitEnumDeclaration(node: EnumDeclaration) {
emitLeadingComments(node);
if (!(node.flags & NodeFlags.Export)) {
@ -1741,7 +1761,10 @@ module ts {
}
function emitModuleDeclaration(node: ModuleDeclaration) {
if (!isInstantiated(node)) return;
if (!isInstantiated(node)) {
return emitPinnedOrTripleSlashComments(node);
}
emitLeadingComments(node);
if (!(node.flags & NodeFlags.Export)) {
emitStart(node);
@ -1969,7 +1992,14 @@ module ts {
}
function emitNode(node: Node) {
if (!node || node.flags & NodeFlags.Ambient) return;
if (!node) {
return;
}
if (node.flags & NodeFlags.Ambient) {
return emitPinnedOrTripleSlashComments(node);
}
switch (node.kind) {
case SyntaxKind.Identifier:
return emitIdentifier(<Identifier>node);
@ -2073,6 +2103,8 @@ module ts {
return emitVariableDeclaration(<VariableDeclaration>node);
case SyntaxKind.ClassDeclaration:
return emitClassDeclaration(<ClassDeclaration>node);
case SyntaxKind.InterfaceDeclaration:
return emitInterfaceDeclaration(<InterfaceDeclaration>node);
case SyntaxKind.EnumDeclaration:
return emitEnumDeclaration(<EnumDeclaration>node);
case SyntaxKind.ModuleDeclaration:
@ -2101,7 +2133,7 @@ module ts {
return leadingComments;
}
function emitLeadingDeclarationComments(node: Node) {
function getLeadingCommentsToEmit(node: Node) {
// Emit the leading comments only if the parent's pos doesnt match because parent should take care of emitting these comments
if (node.parent.kind === SyntaxKind.SourceFile || node.pos !== node.parent.pos) {
var leadingComments: Comment[];
@ -2113,12 +2145,17 @@ module ts {
// get the leading comments from the node
leadingComments = getLeadingCommentsOfNode(node, currentSourceFile);
}
emitNewLineBeforeLeadingComments(node, leadingComments, writer);
// Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
emitComments(leadingComments, /*trailingSeparator*/ true, writer, writeComment);
return leadingComments;
}
}
function emitLeadingDeclarationComments(node: Node) {
var leadingComments = getLeadingCommentsToEmit(node);
emitNewLineBeforeLeadingComments(node, leadingComments, writer);
// Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
emitComments(leadingComments, /*trailingSeparator*/ true, writer, writeComment);
}
function emitTrailingDeclarationComments(node: Node) {
// Emit the trailing comments only if the parent's end doesnt match
if (node.parent.kind === SyntaxKind.SourceFile || node.end !== node.parent.end) {
@ -2166,7 +2203,7 @@ module ts {
lastComment = comment;
});
if (detachedComments && detachedComments.length) {
if (detachedComments.length) {
// All comments look like they could have been part of the copyright header. Make
// sure there is at least one blank line between it and the node. If not, it's not
// a copyright header.
@ -2188,6 +2225,28 @@ module ts {
}
}
function emitPinnedOrTripleSlashCommentsOfNode(node: Node) {
var pinnedComments = ts.filter(getLeadingCommentsToEmit(node), isPinnedOrTripleSlashComment);
function isPinnedOrTripleSlashComment(comment: Comment) {
if (currentSourceFile.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk) {
return currentSourceFile.text.charCodeAt(comment.pos + 2) === CharacterCodes.exclamation;
}
// Verify this is /// comment, but do the regexp match only when we first can find /// in the comment text
// so that we dont end up computing comment string and doing match for all // comments
else if (currentSourceFile.text.charCodeAt(comment.pos + 1) === CharacterCodes.slash &&
comment.pos + 2 < comment.end &&
currentSourceFile.text.charCodeAt(comment.pos + 2) === CharacterCodes.slash &&
currentSourceFile.text.substring(comment.pos, comment.end).match(fullTripleSlashReferencePathRegEx)) {
return true;
}
}
emitNewLineBeforeLeadingComments(node, pinnedComments, writer);
// Leading comments are emitted at /*leading comment1 */space/*leading comment*/space
emitComments(pinnedComments, /*trailingSeparator*/ true, writer, writeComment);
}
if (compilerOptions.sourceMap) {
initializeEmitterWithSourceMaps();
}

View file

@ -165,6 +165,8 @@ module ts {
}
}
export var fullTripleSlashReferencePathRegEx = /^(\/\/\/\s*<reference\s+path\s*=\s*)('|")(.+?)\2.*?\/>/
// Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes
// stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; otherwise,
// embedded arrays are flattened and the 'cbNode' callback is invoked for each element. If a callback returns
@ -3506,8 +3508,7 @@ module ts {
file.hasNoDefaultLib = true;
}
else {
var fullReferenceRegEx = /^(\/\/\/\s*<reference\s+path\s*=\s*)('|")(.+?)\2.*?\/>/;
var matchResult = fullReferenceRegEx.exec(comment);
var matchResult = fullTripleSlashReferencePathRegEx.exec(comment);
if (!matchResult) {
var start = range.pos;
var length = range.end - start;

View file

@ -16,3 +16,4 @@ interface Third extends JQueryEventObjectTest, SecondEvent {}
//// [app.js]
///<reference path='jquery.d.ts' />

View file

@ -1,10 +1,20 @@
//// [commentOnAmbientClass1.ts]
//// [tests/cases/compiler/commentOnAmbientClass1.ts] ////
//// [a.ts]
/*! Keep this pinned comment */
declare class C {
}
// Don't keep this comment.
declare class D {
}
//// [b.ts]
///<reference path="a.ts"/>
declare class E extends C {
}
//// [commentOnAmbientClass1.js]
//// [a.js]
/*! Keep this pinned comment */
//// [b.js]
///<reference path="a.ts"/>

View file

@ -1,4 +1,10 @@
=== tests/cases/compiler/commentOnAmbientClass1.ts ===
=== tests/cases/compiler/b.ts ===
///<reference path="a.ts"/>
declare class E extends C {
>E : E
>C : C
}
=== tests/cases/compiler/a.ts ===
/*! Keep this pinned comment */
declare class C {
>C : C
@ -8,3 +14,4 @@ declare class C {
declare class D {
>D : D
}

View file

@ -0,0 +1,23 @@
//// [tests/cases/compiler/commentOnAmbientEnum.ts] ////
//// [a.ts]
/*! Keep this pinned comment */
declare enum C {
a,
b,
c
}
// Don't keep this comment.
declare enum D {
}
//// [b.ts]
///<reference path="a.ts"/>
declare enum E {
}
//// [a.js]
/*! Keep this pinned comment */
//// [b.js]
///<reference path="a.ts"/>

View file

@ -0,0 +1,25 @@
=== tests/cases/compiler/b.ts ===
///<reference path="a.ts"/>
declare enum E {
>E : E
}
=== tests/cases/compiler/a.ts ===
/*! Keep this pinned comment */
declare enum C {
>C : C
a,
>a : C
b,
>b : C
c
>c : C
}
// Don't keep this comment.
declare enum D {
>D : D
}

View file

@ -0,0 +1,25 @@
//// [tests/cases/compiler/commentOnAmbientModule.ts] ////
//// [a.ts]
/*! Keep this pinned comment */
declare module C {
function foo();
}
// Don't keep this comment.
declare module D {
class bar { }
}
//// [b.ts]
///<reference path="a.ts"/>
declare module E {
class foobar extends D.bar {
foo();
}
}
//// [a.js]
/*! Keep this pinned comment */
//// [b.js]
///<reference path="a.ts"/>

View file

@ -0,0 +1,31 @@
=== tests/cases/compiler/b.ts ===
///<reference path="a.ts"/>
declare module E {
>E : typeof E
class foobar extends D.bar {
>foobar : foobar
>D : D
>bar : bar
foo();
>foo : () => any
}
}
=== tests/cases/compiler/a.ts ===
/*! Keep this pinned comment */
declare module C {
>C : typeof C
function foo();
>foo : () => any
}
// Don't keep this comment.
declare module D {
>D : typeof D
class bar { }
>bar : bar
}

View file

@ -6,3 +6,4 @@ declare var v: number;
declare var y: number;
//// [commentOnAmbientVariable1.js]
/*! Keep this pinned comment */

View file

@ -11,4 +11,5 @@ x = 2;
//// [commentOnAmbientVariable2_1.js]
var y = 1;
//// [commentOnAmbientVariable2_2.js]
/// <reference path='commentOnAmbientVariable2_1.ts'/>
x = 2;

View file

@ -0,0 +1,17 @@
//// [tests/cases/compiler/commentOnAmbientfunction.ts] ////
//// [a.ts]
/*! Keep this pinned comment */
declare function foo();
// Don't keep this comment.
declare function bar();
//// [b.ts]
///<reference path="a.ts"/>
declare function foobar(a: typeof foo): typeof bar;
//// [a.js]
/*! Keep this pinned comment */
//// [b.js]
///<reference path="a.ts"/>

View file

@ -0,0 +1,17 @@
=== tests/cases/compiler/b.ts ===
///<reference path="a.ts"/>
declare function foobar(a: typeof foo): typeof bar;
>foobar : (a: () => any) => () => any
>a : () => any
>foo : () => any
>bar : () => any
=== tests/cases/compiler/a.ts ===
/*! Keep this pinned comment */
declare function foo();
>foo : () => any
// Don't keep this comment.
declare function bar();
>bar : () => any

View file

@ -1,10 +1,20 @@
//// [commentOnElidedModule1.ts]
//// [tests/cases/compiler/commentOnElidedModule1.ts] ////
//// [a.ts]
/*! Keep this pinned comment */
module ElidedModule {
}
// Don't keep this comment.
module ElidedModule2 {
}
//// [b.ts]
///<reference path="a.ts"/>
module ElidedModule3 {
}
//// [commentOnElidedModule1.js]
//// [a.js]
/*! Keep this pinned comment */
//// [b.js]
///<reference path="a.ts"/>

View file

@ -1,4 +1,9 @@
=== tests/cases/compiler/commentOnElidedModule1.ts ===
=== tests/cases/compiler/b.ts ===
///<reference path="a.ts"/>
module ElidedModule3 {
>ElidedModule3 : ElidedModule3
}
=== tests/cases/compiler/a.ts ===
/*! Keep this pinned comment */
module ElidedModule {
>ElidedModule : ElidedModule
@ -8,3 +13,4 @@ module ElidedModule {
module ElidedModule2 {
>ElidedModule2 : ElidedModule2
}

View file

@ -1,10 +1,20 @@
//// [commentOnInterface1.ts]
//// [tests/cases/compiler/commentOnInterface1.ts] ////
//// [a.ts]
/*! Keep this pinned comment */
interface I {
}
// Don't keep this comment.
interface I2 {
}
//// [b.ts]
///<reference path='a.ts'/>
interface I3 {
}
//// [commentOnInterface1.js]
//// [a.js]
/*! Keep this pinned comment */
//// [b.js]
///<reference path='a.ts'/>

View file

@ -1,4 +1,9 @@
=== tests/cases/compiler/commentOnInterface1.ts ===
=== tests/cases/compiler/b.ts ===
///<reference path='a.ts'/>
interface I3 {
>I3 : I3
}
=== tests/cases/compiler/a.ts ===
/*! Keep this pinned comment */
interface I {
>I : I
@ -8,3 +13,4 @@ interface I {
interface I2 {
>I2 : I2
}

View file

@ -1,11 +1,51 @@
//// [commentOnSignature1.ts]
//// [tests/cases/compiler/commentOnSignature1.ts] ////
//// [a.ts]
/*! Keep this pinned comment */
function foo(n: number): void;
// Don't keep this comment.
function foo(s: string): void;
function foo(a: any): void {
}
class c {
// dont keep this comment
constructor(a: string);
/*! keep this pinned comment */
constructor(a: number);
constructor(a: any) {
}
// dont keep this comment
foo(a: string);
/*! keep this pinned comment */
foo(a: number);
foo(a: any) {
}
}
//// [b.ts]
///<reference path='a.ts'/>
function foo2(n: number): void;
// Don't keep this comment.
function foo2(s: string): void;
function foo2(a: any): void {
}
//// [commentOnSignature1.js]
//// [a.js]
/*! Keep this pinned comment */
function foo(a) {
}
var c = (function () {
/*! keep this pinned comment */
function c(a) {
}
/*! keep this pinned comment */
c.prototype.foo = function (a) {
};
return c;
})();
//// [b.js]
///<reference path='a.ts'/>
function foo2(a) {
}

View file

@ -1,4 +1,19 @@
=== tests/cases/compiler/commentOnSignature1.ts ===
=== tests/cases/compiler/b.ts ===
///<reference path='a.ts'/>
function foo2(n: number): void;
>foo2 : { (n: number): void; (s: string): void; }
>n : number
// Don't keep this comment.
function foo2(s: string): void;
>foo2 : { (n: number): void; (s: string): void; }
>s : string
function foo2(a: any): void {
>foo2 : { (n: number): void; (s: string): void; }
>a : any
}
=== tests/cases/compiler/a.ts ===
/*! Keep this pinned comment */
function foo(n: number): void;
>foo : { (n: number): void; (s: string): void; }
@ -13,3 +28,35 @@ function foo(a: any): void {
>foo : { (n: number): void; (s: string): void; }
>a : any
}
class c {
>c : c
// dont keep this comment
constructor(a: string);
>a : string
/*! keep this pinned comment */
constructor(a: number);
>a : number
constructor(a: any) {
>a : any
}
// dont keep this comment
foo(a: string);
>foo : { (a: string): any; (a: number): any; }
>a : string
/*! keep this pinned comment */
foo(a: number);
>foo : { (a: string): any; (a: number): any; }
>a : number
foo(a: any) {
>foo : { (a: string): any; (a: number): any; }
>a : any
}
}

View file

@ -22,3 +22,4 @@ interface C {
var q1;
var x = q1.each(function (x) { return c.log(x); });
//// [file2.js]
///<reference path='file1.ts'/>

View file

@ -49,6 +49,8 @@ var Microsoft;
/// <reference path="emitMemberAccessExpression_file3.ts" />
"use strict";
//// [emitMemberAccessExpression_file3.js]
/// <reference path="emitMemberAccessExpression_file2.ts" />
/// <reference path="emitMemberAccessExpression_file1.ts" />
var Microsoft;
(function (Microsoft) {
(function (PeopleAtWork) {

View file

@ -17,6 +17,7 @@ module bar {
//// [reuseInnerModuleMember_0.js]
//// [reuseInnerModuleMember_1.js]
///<reference path='reuseInnerModuleMember_0.ts'/>
var bar;
(function (bar) {
var x;

View file

@ -1,7 +1,13 @@
//@filename: a.ts
/*! Keep this pinned comment */
declare class C {
}
// Don't keep this comment.
declare class D {
}
//@filename: b.ts
///<reference path="a.ts"/>
declare class E extends C {
}

View file

@ -0,0 +1,16 @@
//@filename: a.ts
/*! Keep this pinned comment */
declare enum C {
a,
b,
c
}
// Don't keep this comment.
declare enum D {
}
//@filename: b.ts
///<reference path="a.ts"/>
declare enum E {
}

View file

@ -0,0 +1,18 @@
//@filename: a.ts
/*! Keep this pinned comment */
declare module C {
function foo();
}
// Don't keep this comment.
declare module D {
class bar { }
}
//@filename: b.ts
///<reference path="a.ts"/>
declare module E {
class foobar extends D.bar {
foo();
}
}

View file

@ -0,0 +1,10 @@
//@filename: a.ts
/*! Keep this pinned comment */
declare function foo();
// Don't keep this comment.
declare function bar();
//@filename: b.ts
///<reference path="a.ts"/>
declare function foobar(a: typeof foo): typeof bar;

View file

@ -1,7 +1,13 @@
//@filename: a.ts
/*! Keep this pinned comment */
module ElidedModule {
}
// Don't keep this comment.
module ElidedModule2 {
}
//@filename: b.ts
///<reference path="a.ts"/>
module ElidedModule3 {
}

View file

@ -1,7 +1,13 @@
//@filename: a.ts
/*! Keep this pinned comment */
interface I {
}
// Don't keep this comment.
interface I2 {
}
//@filename: b.ts
///<reference path='a.ts'/>
interface I3 {
}

View file

@ -1,6 +1,31 @@
// @filename: a.ts
/*! Keep this pinned comment */
function foo(n: number): void;
// Don't keep this comment.
function foo(s: string): void;
function foo(a: any): void {
}
class c {
// dont keep this comment
constructor(a: string);
/*! keep this pinned comment */
constructor(a: number);
constructor(a: any) {
}
// dont keep this comment
foo(a: string);
/*! keep this pinned comment */
foo(a: number);
foo(a: any) {
}
}
//@filename:b.ts
///<reference path='a.ts'/>
function foo2(n: number): void;
// Don't keep this comment.
function foo2(s: string): void;
function foo2(a: any): void {
}