Skip to content

Copyright comments are not preserved when generating d.ts files #5472

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 2, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/compiler/declarationEmitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,7 @@ namespace ts {
function emitSourceFile(node: SourceFile) {
currentSourceFile = node;
enclosingDeclaration = node;
emitDetachedComments(currentSourceFile, writer, writeCommentRange, node, newLine, true /* remove comments */);
emitLines(node.statements);
}

Expand Down
76 changes: 12 additions & 64 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4907,7 +4907,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi

increaseIndent();
let outPos = writer.getTextPos();
emitDetachedComments(node.body);
emitDetachedCommentsAndUpdateCommentsInfo(node.body);
emitFunctionBodyPreamble(node);
let preambleEmitted = writer.getTextPos() !== outPos;
decreaseIndent();
Expand Down Expand Up @@ -4952,7 +4952,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
let initialTextPos = writer.getTextPos();

increaseIndent();
emitDetachedComments(body.statements);
emitDetachedCommentsAndUpdateCommentsInfo(body.statements);

// Emit all the directive prologues (like "use strict"). These have to come before
// any other preamble code we write (like parameter initializers).
Expand Down Expand Up @@ -5274,7 +5274,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
// Emit all the directive prologues (like "use strict"). These have to come before
// any other preamble code we write (like parameter initializers).
startIndex = emitDirectivePrologues(ctor.body.statements, /*startWithNewLine*/ true);
emitDetachedComments(ctor.body.statements);
emitDetachedCommentsAndUpdateCommentsInfo(ctor.body.statements);
}
emitCaptureThisForNodeIfNecessary(node);
let superCall: ExpressionStatement;
Expand Down Expand Up @@ -7652,7 +7652,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
// Start new file on new line
writeLine();
emitShebang();
emitDetachedComments(node);
emitDetachedCommentsAndUpdateCommentsInfo(node);

if (isExternalModule(node) || compilerOptions.isolatedModules) {
let emitModule = moduleEmitDelegates[modulekind] || moduleEmitDelegates[ModuleKind.CommonJS];
Expand Down Expand Up @@ -7948,11 +7948,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
return leadingComments;
}

function isPinnedComments(comment: CommentRange) {
return currentSourceFile.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk &&
currentSourceFile.text.charCodeAt(comment.pos + 2) === CharacterCodes.exclamation;
}

/**
* Determine if the given comment is a triple-slash
*
Expand Down Expand Up @@ -8086,62 +8081,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
emitComments(currentSourceFile, writer, leadingComments, /*trailingSeparator*/ true, newLine, writeComment);
}

function emitDetachedComments(node: TextRange) {
let leadingComments: CommentRange[];
if (compilerOptions.removeComments) {
// removeComments is true, only reserve pinned comment at the top of file
// For example:
// /*! Pinned Comment */
//
// var x = 10;
if (node.pos === 0) {
leadingComments = filter(getLeadingCommentRanges(currentSourceFile.text, node.pos), isPinnedComments);
}
}
else {
// removeComments is false, just get detached as normal and bypass the process to filter comment
leadingComments = getLeadingCommentRanges(currentSourceFile.text, node.pos);
}

if (leadingComments) {
let detachedComments: CommentRange[] = [];
let lastComment: CommentRange;

forEach(leadingComments, comment => {
if (lastComment) {
let lastCommentLine = getLineOfLocalPosition(currentSourceFile, lastComment.end);
let commentLine = getLineOfLocalPosition(currentSourceFile, comment.pos);
function emitDetachedCommentsAndUpdateCommentsInfo(node: TextRange) {
let currentDetachedCommentInfo = emitDetachedComments(currentSourceFile, writer, writeComment, node, newLine, compilerOptions.removeComments);

if (commentLine >= lastCommentLine + 2) {
// There was a blank line between the last comment and this comment. This
// comment is not part of the copyright comments. Return what we have so
// far.
return detachedComments;
}
}

detachedComments.push(comment);
lastComment = comment;
});

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.
let lastCommentLine = getLineOfLocalPosition(currentSourceFile, lastOrUndefined(detachedComments).end);
let nodeLine = getLineOfLocalPosition(currentSourceFile, skipTrivia(currentSourceFile.text, node.pos));
if (nodeLine >= lastCommentLine + 2) {
// Valid detachedComments
emitNewLineBeforeLeadingComments(currentSourceFile, writer, node, leadingComments);
emitComments(currentSourceFile, writer, detachedComments, /*trailingSeparator*/ true, newLine, writeComment);
let currentDetachedCommentInfo = { nodePos: node.pos, detachedCommentEndPos: lastOrUndefined(detachedComments).end };
if (detachedCommentsInfo) {
detachedCommentsInfo.push(currentDetachedCommentInfo);
}
else {
detachedCommentsInfo = [currentDetachedCommentInfo];
}
}
if (currentDetachedCommentInfo) {
if (detachedCommentsInfo) {
detachedCommentsInfo.push(currentDetachedCommentInfo);
}
else {
detachedCommentsInfo = [currentDetachedCommentInfo];
}
}
}
Expand Down
68 changes: 68 additions & 0 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1904,6 +1904,74 @@ namespace ts {
});
}

/**
* Detached comment is a comment at the top of file or function body that is separated from
* the next statement by space.
*/
export function emitDetachedComments(currentSourceFile: SourceFile, writer: EmitTextWriter,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A quick JSDoc comment would be helpful here.

writeComment: (currentSourceFile: SourceFile, writer: EmitTextWriter, comment: CommentRange, newLine: string) => void,
node: TextRange, newLine: string, removeComments: boolean) {
let leadingComments: CommentRange[];
let currentDetachedCommentInfo: {nodePos: number, detachedCommentEndPos: number};
if (removeComments) {
// removeComments is true, only reserve pinned comment at the top of file
// For example:
// /*! Pinned Comment */
//
// var x = 10;
if (node.pos === 0) {
leadingComments = filter(getLeadingCommentRanges(currentSourceFile.text, node.pos), isPinnedComment);
}
}
else {
// removeComments is false, just get detached as normal and bypass the process to filter comment
leadingComments = getLeadingCommentRanges(currentSourceFile.text, node.pos);
}

if (leadingComments) {
let detachedComments: CommentRange[] = [];
let lastComment: CommentRange;

for (let comment of leadingComments) {
if (lastComment) {
let lastCommentLine = getLineOfLocalPosition(currentSourceFile, lastComment.end);
let commentLine = getLineOfLocalPosition(currentSourceFile, comment.pos);

if (commentLine >= lastCommentLine + 2) {
// There was a blank line between the last comment and this comment. This
// comment is not part of the copyright comments. Return what we have so
// far.
break;
}
}

detachedComments.push(comment);
lastComment = comment;
}

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.
let lastCommentLine = getLineOfLocalPosition(currentSourceFile, lastOrUndefined(detachedComments).end);
let nodeLine = getLineOfLocalPosition(currentSourceFile, skipTrivia(currentSourceFile.text, node.pos));
if (nodeLine >= lastCommentLine + 2) {
// Valid detachedComments
emitNewLineBeforeLeadingComments(currentSourceFile, writer, node, leadingComments);
emitComments(currentSourceFile, writer, detachedComments, /*trailingSeparator*/ true, newLine, writeComment);
currentDetachedCommentInfo = { nodePos: node.pos, detachedCommentEndPos: lastOrUndefined(detachedComments).end };
}
}
}

return currentDetachedCommentInfo;

function isPinnedComment(comment: CommentRange) {
return currentSourceFile.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk &&
currentSourceFile.text.charCodeAt(comment.pos + 2) === CharacterCodes.exclamation;
}
}

export function writeCommentRange(currentSourceFile: SourceFile, writer: EmitTextWriter, comment: CommentRange, newLine: string) {
if (currentSourceFile.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk) {
let firstCommentLineAndCharacter = getLineAndCharacterOfPosition(currentSourceFile, comment.pos);
Expand Down
85 changes: 85 additions & 0 deletions tests/baselines/reference/declarationEmitDetachedComment1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//// [tests/cases/compiler/declarationEmitDetachedComment1.ts] ////

//// [test1.ts]

/*! Copyright 2015 MyCompany Inc. */

/**
* Hello class
*/
class Hello {

}

//// [test2.ts]
/* A comment at the top of the file. */

/**
* Hi class
*/
class Hi {

}

//// [test3.ts]
// A one-line comment at the top of the file.

/**
* Hola class
*/
class Hola {

}


//// [test1.js]
/*! Copyright 2015 MyCompany Inc. */
/**
* Hello class
*/
var Hello = (function () {
function Hello() {
}
return Hello;
})();
//// [test2.js]
/* A comment at the top of the file. */
/**
* Hi class
*/
var Hi = (function () {
function Hi() {
}
return Hi;
})();
//// [test3.js]
// A one-line comment at the top of the file.
/**
* Hola class
*/
var Hola = (function () {
function Hola() {
}
return Hola;
})();


//// [test1.d.ts]
/*! Copyright 2015 MyCompany Inc. */
/**
* Hello class
*/
declare class Hello {
}
//// [test2.d.ts]
/**
* Hi class
*/
declare class Hi {
}
//// [test3.d.ts]
/**
* Hola class
*/
declare class Hola {
}
34 changes: 34 additions & 0 deletions tests/baselines/reference/declarationEmitDetachedComment1.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
=== tests/cases/compiler/test1.ts ===

/*! Copyright 2015 MyCompany Inc. */

/**
* Hello class
*/
class Hello {
>Hello : Symbol(Hello, Decl(test1.ts, 0, 0))

}

=== tests/cases/compiler/test2.ts ===
/* A comment at the top of the file. */

/**
* Hi class
*/
class Hi {
>Hi : Symbol(Hi, Decl(test2.ts, 0, 0))

}

=== tests/cases/compiler/test3.ts ===
// A one-line comment at the top of the file.

/**
* Hola class
*/
class Hola {
>Hola : Symbol(Hola, Decl(test3.ts, 0, 0))

}

34 changes: 34 additions & 0 deletions tests/baselines/reference/declarationEmitDetachedComment1.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
=== tests/cases/compiler/test1.ts ===

/*! Copyright 2015 MyCompany Inc. */

/**
* Hello class
*/
class Hello {
>Hello : Hello

}

=== tests/cases/compiler/test2.ts ===
/* A comment at the top of the file. */

/**
* Hi class
*/
class Hi {
>Hi : Hi

}

=== tests/cases/compiler/test3.ts ===
// A one-line comment at the top of the file.

/**
* Hola class
*/
class Hola {
>Hola : Hola

}

Loading