Merge pull request #5472 from MartyIX/issue-5183

Fix copyright comments are not preserved when generating d.ts files
This commit is contained in:
Yui 2015-11-02 11:21:47 -08:00
commit f503169f8c
11 changed files with 435 additions and 64 deletions

View file

@ -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);
}

View file

@ -4899,7 +4899,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();
@ -4944,7 +4944,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).
@ -5266,7 +5266,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;
@ -7644,7 +7644,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];
@ -7940,11 +7940,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
*
@ -8078,62 +8073,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);
function emitDetachedCommentsAndUpdateCommentsInfo(node: TextRange) {
let currentDetachedCommentInfo = emitDetachedComments(currentSourceFile, writer, writeComment, node, newLine, compilerOptions.removeComments);
if (currentDetachedCommentInfo) {
if (detachedCommentsInfo) {
detachedCommentsInfo.push(currentDetachedCommentInfo);
}
}
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);
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];
}
}
else {
detachedCommentsInfo = [currentDetachedCommentInfo];
}
}
}

View file

@ -1912,6 +1912,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,
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);

View file

@ -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 {
}

View file

@ -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))
}

View file

@ -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
}

View file

@ -0,0 +1,65 @@
//// [tests/cases/compiler/declarationEmitDetachedComment2.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. */
var Hello = (function () {
function Hello() {
}
return Hello;
})();
//// [test2.js]
var Hi = (function () {
function Hi() {
}
return Hi;
})();
//// [test3.js]
var Hola = (function () {
function Hola() {
}
return Hola;
})();
//// [test1.d.ts]
/*! Copyright 2015 MyCompany Inc. */
declare class Hello {
}
//// [test2.d.ts]
declare class Hi {
}
//// [test3.d.ts]
declare class Hola {
}

View file

@ -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))
}

View file

@ -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
}

View file

@ -0,0 +1,34 @@
// @target: es5
// @module: commonjs
// @declaration: true
// @removeComments: false
// @filename: test1.ts
/*! Copyright 2015 MyCompany Inc. */
/**
* Hello class
*/
class Hello {
}
// @filename: test2.ts
/* A comment at the top of the file. */
/**
* Hi class
*/
class Hi {
}
// @filename: test3.ts
// A one-line comment at the top of the file.
/**
* Hola class
*/
class Hola {
}

View file

@ -0,0 +1,34 @@
// @target: es5
// @module: commonjs
// @declaration: true
// @removeComments: true
// @filename: test1.ts
/*! Copyright 2015 MyCompany Inc. */
/**
* Hello class
*/
class Hello {
}
// @filename: test2.ts
/* A comment at the top of the file. */
/**
* Hi class
*/
class Hi {
}
// @filename: test3.ts
// A one-line comment at the top of the file.
/**
* Hola class
*/
class Hola {
}