diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 6f3491ed1fa..ae0830a87ee 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -167,6 +167,21 @@ module ts { }); } + function emitComments(comments: Comment[], writer: EmitTextWriter, writeComment: (comment: Comment, writer: EmitTextWriter) => void) { + forEach(comments, comment => { + writeComment(comment, writer); + if (comment.hasTrailingNewLine) { + writer.writeLine(); + } else { + writer.write(" "); + } + }); + } + + function writeCommentRange(comment: Comment, writer: EmitTextWriter) { + writer.writeLiteral(currentSourceFile.text.substring(comment.pos, comment.end)); + } + function emitJavaScript(jsFilePath: string, root?: SourceFile) { var writer = createTextWriter(writeSymbol); var write = writer.write; @@ -440,9 +455,9 @@ module ts { sourceMapNameIndices.pop(); }; - function writeCommentRangeWithMap(comment: Comment) { + function writeCommentRangeWithMap(comment: Comment, writer: EmitTextWriter) { recordSourceMapSpan(comment.pos); - writeCommentRange(comment); + writeCommentRange(comment, writer); recordSourceMapSpan(comment.end); } @@ -1908,24 +1923,9 @@ module ts { } } - function writeCommentRange(comment: Comment) { - writer.writeLiteral(currentSourceFile.text.substring(comment.pos, comment.end)); - } - - function emitComments(comments: Comment[]) { - forEach(comments, comment => { - writeComment(comment); - if (comment.hasTrailingNewLine) { - writer.writeLine(); - } else { - writer.write(" "); - } - }); - } - function emitLeadingDeclarationComments(node: Declaration) { var leadingComments = getLeadingComments(currentSourceFile.text, node.pos); - emitComments(leadingComments); + emitComments(leadingComments, writer, writeComment); } function emitTrailingDeclarationComments(node: Declaration) { @@ -1961,6 +1961,8 @@ module ts { var enclosingDeclaration: Node; var reportedDeclarationError = false; + var emitJsDocComments = compilerOptions.removeComments ? function (declaration: Declaration) { } : writeJsDocComments; + var aliasDeclarationEmitInfo: { declaration: ImportDeclaration; outputPos: number; @@ -2038,6 +2040,11 @@ module ts { } } + function writeJsDocComments(declaration: Declaration) { + var jsDocComments = getJsDocComments(declaration, currentSourceFile); + emitComments(jsDocComments, writer, writeCommentRange); + } + function emitSourceTextOfNode(node: Node) { write(getSourceTextOfLocalNode(node)); } @@ -2096,6 +2103,7 @@ module ts { function writeImportDeclaration(node: ImportDeclaration) { // note usage of writer. methods instead of aliases created, just to make sure we are using // correct writer especially to handle asynchronous alias writing + emitJsDocComments(node); if (node.flags & NodeFlags.Export) { writer.write("export "); } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 74b3f59bbd1..456ba2f8f12 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -139,6 +139,35 @@ module ts { return ((node).expression).text === "use strict"; } + export function getJsDocComments(node: Declaration, sourceFileOfNode: SourceFile) { + var comments: Comment[]; + if (node.kind === SyntaxKind.Parameter) { + // First check if the parameter was written like so: + // ( + // /** blah */ a, + // /** blah */ b); + comments = getLeadingComments(sourceFileOfNode.text, node.pos); + if (!comments) { + // Now check if it was written like so: + // (/** blah */ a, /** blah */ b); + // In this case, the comment will belong to the preceding token. + comments = getTrailingComments(sourceFileOfNode.text, node.pos); + } + } + else { + comments = getLeadingComments(sourceFileOfNode.text, node.pos); + } + + return filter(comments, comment => isJsDocComment(comment)); + + function isJsDocComment(comment: Comment) { + // js doc is if comment is starting with /** but not if it is /**/ + return sourceFileOfNode.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk && + sourceFileOfNode.text.charCodeAt(comment.pos + 2) === CharacterCodes.asterisk && + sourceFileOfNode.text.charCodeAt(comment.pos + 3) !== CharacterCodes.slash; + } + } + // 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 diff --git a/tests/baselines/reference/commentsExternalModules2.js b/tests/baselines/reference/commentsExternalModules2.js new file mode 100644 index 00000000000..db3823ff00b --- /dev/null +++ b/tests/baselines/reference/commentsExternalModules2.js @@ -0,0 +1,163 @@ +//// [tests/cases/compiler/commentsExternalModules2.ts] //// + +//// [commentsExternalModules2_0.ts] + +/** Module comment*/ +export module m1 { + /** b's comment*/ + export var b: number; + /** foo's comment*/ + function foo() { + return b; + } + /** m2 comments*/ + export module m2 { + /** class comment;*/ + export class c { + }; + /** i*/ + export var i = new c(); + } + /** exported function*/ + export function fooExport() { + return foo(); + } +} +m1.fooExport(); +var myvar = new m1.m2.c(); + +/** Module comment */ +export module m4 { + /** b's comment */ + export var b: number; + /** foo's comment + */ + function foo() { + return b; + } + /** m2 comments + */ + export module m2 { + /** class comment; */ + export class c { + }; + /** i */ + export var i = new c(); + } + /** exported function */ + export function fooExport() { + return foo(); + } +} +m4.fooExport(); +var myvar2 = new m4.m2.c(); + +//// [commentsExternalModules_1.ts] +/**This is on import declaration*/ +import extMod = require("commentsExternalModules2_0"); +extMod.m1.fooExport(); +export var newVar = new extMod.m1.m2.c(); +extMod.m4.fooExport(); +export var newVar2 = new extMod.m4.m2.c(); + + +//// [commentsExternalModules2_0.js] +define(["require", "exports"], function (require, exports) { + /** Module comment*/ + (function (m1) { + /** b's comment*/ + m1.b; + /** foo's comment*/ + function foo() { + return m1.b; + } + /** m2 comments*/ + (function (m2) { + /** class comment;*/ + var c = (function () { + function c() { + } + return c; + })(); + m2.c = c; + ; + /** i*/ + m2.i = new c(); + })(m1.m2 || (m1.m2 = {})); + var m2 = m1.m2; + /** exported function*/ + function fooExport() { + return foo(); + } + m1.fooExport = fooExport; + })(exports.m1 || (exports.m1 = {})); + var m1 = exports.m1; + m1.fooExport(); + var myvar = new m1.m2.c(); + /** Module comment */ + (function (m4) { + /** b's comment */ + m4.b; + /** foo's comment + */ + function foo() { + return m4.b; + } + /** m2 comments + */ + (function (m2) { + /** class comment; */ + var c = (function () { + function c() { + } + return c; + })(); + m2.c = c; + ; + /** i */ + m2.i = new c(); + })(m4.m2 || (m4.m2 = {})); + var m2 = m4.m2; + /** exported function */ + function fooExport() { + return foo(); + } + m4.fooExport = fooExport; + })(exports.m4 || (exports.m4 = {})); + var m4 = exports.m4; + m4.fooExport(); + var myvar2 = new m4.m2.c(); +}); +//// [commentsExternalModules_1.js] +define(["require", "exports", "commentsExternalModules2_0"], function (require, exports, extMod) { + extMod.m1.fooExport(); + exports.newVar = new extMod.m1.m2.c(); + extMod.m4.fooExport(); + exports.newVar2 = new extMod.m4.m2.c(); +}); + + +//// [commentsExternalModules2_0.d.ts] +export declare module m1 { + var b: number; + module m2 { + class c { + } + var i: c; + } + function fooExport(): number; +} +export declare module m4 { + var b: number; + module m2 { + class c { + } + var i: c; + } + function fooExport(): number; +} +//// [commentsExternalModules_1.d.ts] +/**This is on import declaration*/ +import extMod = require("commentsExternalModules2_0"); +export declare var newVar: extMod.m1.m2.c; +export declare var newVar2: extMod.m4.m2.c; diff --git a/tests/baselines/reference/declFileImportModuleWithExportAssignment.js b/tests/baselines/reference/declFileImportModuleWithExportAssignment.js index b6edb961b36..145d4ad3ff2 100644 --- a/tests/baselines/reference/declFileImportModuleWithExportAssignment.js +++ b/tests/baselines/reference/declFileImportModuleWithExportAssignment.js @@ -53,6 +53,7 @@ declare var m2: { }; export = m2; //// [declFileImportModuleWithExportAssignment_1.d.ts] +/**This is on import declaration*/ import a1 = require("declFileImportModuleWithExportAssignment_0"); export declare var a: { (): a1.connectExport; diff --git a/tests/cases/compiler/commentsExternalModules2.ts b/tests/cases/compiler/commentsExternalModules2.ts new file mode 100644 index 00000000000..76f00e4fe96 --- /dev/null +++ b/tests/cases/compiler/commentsExternalModules2.ts @@ -0,0 +1,63 @@ +//@module: amd +// @target: ES5 +// @declaration: true +// @comments: true + +// @Filename: commentsExternalModules2_0.ts +/** Module comment*/ +export module m1 { + /** b's comment*/ + export var b: number; + /** foo's comment*/ + function foo() { + return b; + } + /** m2 comments*/ + export module m2 { + /** class comment;*/ + export class c { + }; + /** i*/ + export var i = new c(); + } + /** exported function*/ + export function fooExport() { + return foo(); + } +} +m1.fooExport(); +var myvar = new m1.m2.c(); + +/** Module comment */ +export module m4 { + /** b's comment */ + export var b: number; + /** foo's comment + */ + function foo() { + return b; + } + /** m2 comments + */ + export module m2 { + /** class comment; */ + export class c { + }; + /** i */ + export var i = new c(); + } + /** exported function */ + export function fooExport() { + return foo(); + } +} +m4.fooExport(); +var myvar2 = new m4.m2.c(); + +// @Filename: commentsExternalModules_1.ts +/**This is on import declaration*/ +import extMod = require("commentsExternalModules2_0"); +extMod.m1.fooExport(); +export var newVar = new extMod.m1.m2.c(); +extMod.m4.fooExport(); +export var newVar2 = new extMod.m4.m2.c();