Skip to content

Commit e0faa65

Browse files
committed
Merge pull request #455 from Microsoft/formatComment
Align the multiline comments in the generated outputs by retaining its position relative to the first line in the comment
2 parents 94e0d95 + 6ad8fa6 commit e0faa65

37 files changed

+625
-210
lines changed

src/compiler/emitter.ts

Lines changed: 114 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,24 @@
55

66
module ts {
77
interface EmitTextWriter extends TextWriter {
8+
rawWrite(s: string): void;
89
writeLiteral(s: string): void;
910
getTextPos(): number;
1011
getLine(): number;
1112
getColumn(): number;
1213
getIndent(): number;
13-
isLineStart(): boolean;
1414
}
1515

16-
var indentStrings: string[] = [];
16+
var indentStrings: string[] = ["", " "];
1717
function getIndentString(level: number) {
18-
return indentStrings[level] || (indentStrings[level] = level === 0 ? "" : getIndentString(level - 1) + " ");
18+
if (indentStrings[level] === undefined) {
19+
indentStrings[level] = getIndentString(level - 1) + indentStrings[1];
20+
}
21+
return indentStrings[level];
22+
}
23+
24+
function getIndentSize() {
25+
return indentStrings[1].length;
1926
}
2027

2128
export function emitFiles(resolver: EmitResolver): EmitResult {
@@ -108,6 +115,15 @@ module ts {
108115
}
109116
}
110117

118+
function rawWrite(s: string) {
119+
if (s !== undefined) {
120+
if (lineStart) {
121+
lineStart = false;
122+
}
123+
output += s;
124+
}
125+
}
126+
111127
function writeLiteral(s: string) {
112128
if (s && s.length) {
113129
write(s);
@@ -139,16 +155,16 @@ module ts {
139155
return {
140156
write: write,
141157
writeSymbol: writeSymbol,
158+
rawWrite: rawWrite,
142159
writeLiteral: writeLiteral,
143160
writeLine: writeLine,
144161
increaseIndent: () => indent++,
145162
decreaseIndent: () => indent--,
146163
getIndent: () => indent,
147164
getTextPos: () => output.length,
148165
getLine: () => lineCount + 1,
149-
getColumn: () => lineStart ? indent * 4 + 1 : output.length - linePos + 1,
166+
getColumn: () => lineStart ? indent * getIndentSize() + 1 : output.length - linePos + 1,
150167
getText: () => output,
151-
isLineStart: () => lineStart
152168
};
153169
}
154170

@@ -196,7 +212,99 @@ module ts {
196212
}
197213

198214
function writeCommentRange(comment: Comment, writer: EmitTextWriter) {
199-
writer.writeLiteral(currentSourceFile.text.substring(comment.pos, comment.end));
215+
if (currentSourceFile.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk) {
216+
var firstCommentLineAndCharacter = currentSourceFile.getLineAndCharacterFromPosition(comment.pos);
217+
var firstCommentLineIndent: number;
218+
for (var pos = comment.pos, currentLine = firstCommentLineAndCharacter.line; pos < comment.end; currentLine++) {
219+
var nextLineStart = currentSourceFile.getPositionFromLineAndCharacter(currentLine + 1, /*character*/1);
220+
221+
if (pos !== comment.pos) {
222+
// If we are not emitting first line, we need to write the spaces to adjust the alignment
223+
if (firstCommentLineIndent === undefined) {
224+
firstCommentLineIndent = calculateIndent(currentSourceFile.getPositionFromLineAndCharacter(firstCommentLineAndCharacter.line, /*character*/1),
225+
comment.pos);
226+
}
227+
228+
// These are number of spaces writer is going to write at current indent
229+
var currentWriterIndentSpacing = writer.getIndent() * getIndentSize();
230+
231+
// Number of spaces we want to be writing
232+
// eg: Assume writer indent
233+
// module m {
234+
// /* starts at character 9 this is line 1
235+
// * starts at character pos 4 line --1 = 8 - 8 + 3
236+
// More left indented comment */ --2 = 8 - 8 + 2
237+
// class c { }
238+
// }
239+
// module m {
240+
// /* this is line 1 -- Assume current writer indent 8
241+
// * line --3 = 8 - 4 + 5
242+
// More right indented comment */ --4 = 8 - 4 + 11
243+
// class c { }
244+
// }
245+
var spacesToEmit = currentWriterIndentSpacing - firstCommentLineIndent + calculateIndent(pos, nextLineStart);
246+
if (spacesToEmit > 0) {
247+
var numberOfSingleSpacesToEmit = spacesToEmit % getIndentSize();
248+
var indentSizeSpaceString = getIndentString((spacesToEmit - numberOfSingleSpacesToEmit) / getIndentSize());
249+
250+
// Write indent size string ( in eg 1: = "", 2: "" , 3: string with 8 spaces 4: string with 12 spaces
251+
writer.rawWrite(indentSizeSpaceString);
252+
253+
// Emit the single spaces (in eg: 1: 3 spaces, 2: 2 spaces, 3: 1 space, 4: 3 spaces)
254+
while (numberOfSingleSpacesToEmit) {
255+
writer.rawWrite(" ");
256+
numberOfSingleSpacesToEmit--;
257+
}
258+
}
259+
else {
260+
// No spaces to emit write empty string
261+
writer.rawWrite("");
262+
}
263+
}
264+
265+
// Write the comment line text
266+
writeTrimmedCurrentLine(pos, nextLineStart);
267+
268+
pos = nextLineStart;
269+
}
270+
}
271+
else {
272+
// Single line comment of styly //....
273+
writer.write(currentSourceFile.text.substring(comment.pos, comment.end));
274+
}
275+
276+
function writeTrimmedCurrentLine(pos: number, nextLineStart: number) {
277+
var end = Math.min(comment.end, nextLineStart - 1);
278+
var currentLineText = currentSourceFile.text.substring(pos, end).replace(/^\s+|\s+$/g, '');
279+
if (currentLineText) {
280+
// trimmed forward and ending spaces text
281+
writer.write(currentLineText);
282+
if (end !== comment.end) {
283+
writer.writeLine();
284+
}
285+
}
286+
else {
287+
// Empty string - make sure we write empty line
288+
writer.writeLiteral(sys.newLine);
289+
}
290+
}
291+
292+
function calculateIndent(pos: number, end: number) {
293+
var currentLineIndent = 0;
294+
while (pos < end && isWhiteSpace(currentSourceFile.text.charCodeAt(pos))) {
295+
pos++;
296+
if (currentSourceFile.text.charCodeAt(pos) === CharacterCodes.tab) {
297+
// Tabs = size of the indent
298+
currentLineIndent += getIndentSize();
299+
}
300+
else {
301+
// Single space
302+
currentLineIndent++;
303+
}
304+
}
305+
306+
return currentLineIndent;
307+
}
200308
}
201309

202310
function emitJavaScript(jsFilePath: string, root?: SourceFile) {

src/compiler/parser.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,13 @@ module ts {
575575
return getLineAndCharacterOfPosition(lineStarts, position);
576576
}
577577

578+
function getPositionFromSourceLineAndCharacter(line: number, character: number): number {
579+
if (!lineStarts) {
580+
lineStarts = getLineStarts(sourceText);
581+
}
582+
return getPositionFromLineAndCharacter(lineStarts, line, character);
583+
}
584+
578585
function error(message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): void {
579586
var start = scanner.getTokenPos();
580587
var length = scanner.getTextPos() - start;
@@ -3575,6 +3582,7 @@ module ts {
35753582
file.filename = normalizePath(filename);
35763583
file.text = sourceText;
35773584
file.getLineAndCharacterFromPosition = getLineAndCharacterlFromSourcePosition;
3585+
file.getPositionFromLineAndCharacter = getPositionFromSourceLineAndCharacter;
35783586
file.syntacticErrors = [];
35793587
file.semanticErrors = [];
35803588
var referenceComments = processReferenceComments();

src/compiler/scanner.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,11 @@ module ts {
264264
return result;
265265
}
266266

267+
export function getPositionFromLineAndCharacter(lineStarts: number[], line: number, character: number): number {
268+
Debug.assert(line > 0);
269+
return lineStarts[line - 1] + character - 1;
270+
}
271+
267272
export function getLineAndCharacterOfPosition(lineStarts: number[], position: number) {
268273
var lineNumber = binarySearch(lineStarts, position);
269274
if (lineNumber < 0) {
@@ -286,13 +291,13 @@ module ts {
286291

287292
var hasOwnProperty = Object.prototype.hasOwnProperty;
288293

289-
function isWhiteSpace(ch: number): boolean {
294+
export function isWhiteSpace(ch: number): boolean {
290295
return ch === CharacterCodes.space || ch === CharacterCodes.tab || ch === CharacterCodes.verticalTab || ch === CharacterCodes.formFeed ||
291296
ch === CharacterCodes.nonBreakingSpace || ch === CharacterCodes.ogham || ch >= CharacterCodes.enQuad && ch <= CharacterCodes.zeroWidthSpace ||
292297
ch === CharacterCodes.narrowNoBreakSpace || ch === CharacterCodes.mathematicalSpace || ch === CharacterCodes.ideographicSpace || ch === CharacterCodes.byteOrderMark;
293298
}
294299

295-
function isLineBreak(ch: number): boolean {
300+
export function isLineBreak(ch: number): boolean {
296301
return ch === CharacterCodes.lineFeed || ch === CharacterCodes.carriageReturn || ch === CharacterCodes.lineSeparator || ch === CharacterCodes.paragraphSeparator;
297302
}
298303

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,7 @@ module ts {
520520
filename: string;
521521
text: string;
522522
getLineAndCharacterFromPosition(position: number): { line: number; character: number };
523+
getPositionFromLineAndCharacter(line: number, character: number): number;
523524
amdDependencies: string[];
524525
referencedFiles: FileReference[];
525526
syntacticErrors: Diagnostic[];

src/services/services.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ module ts {
310310
public filename: string;
311311
public text: string;
312312
public getLineAndCharacterFromPosition(position: number): { line: number; character: number } { return null; }
313+
public getPositionFromLineAndCharacter(line: number, character: number): number { return -1; }
313314
public amdDependencies: string[];
314315
public referencedFiles: FileReference[];
315316
public syntacticErrors: Diagnostic[];

tests/baselines/reference/arrayAssignmentTest1.js

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -121,16 +121,16 @@ var C3 = (function () {
121121
};
122122
return C3;
123123
})();
124-
/*
125-
126-
This behaves unexpectedly with the following types:
127-
128-
Type 1 of any[]:
129-
130-
* Type 2 of the following throws an error but shouldn't: () => void[], SomeClass[], and {one: 1}[].
131-
132-
* Type 2 of the following doesn't throw an error but should: {one: 1}, new() => SomeClass, SomeClass.
133-
124+
/*
125+
126+
This behaves unexpectedly with the following types:
127+
128+
Type 1 of any[]:
129+
130+
* Type 2 of the following throws an error but shouldn't: () => void[], SomeClass[], and {one: 1}[].
131+
132+
* Type 2 of the following doesn't throw an error but should: {one: 1}, new() => SomeClass, SomeClass.
133+
134134
*/
135135
var a1 = null;
136136
var c1 = new C1();

tests/baselines/reference/arrayAssignmentTest2.js

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -95,16 +95,16 @@ var C3 = (function () {
9595
};
9696
return C3;
9797
})();
98-
/*
99-
100-
This behaves unexpectedly with the following types:
101-
102-
Type 1 of any[]:
103-
104-
* Type 2 of the following throws an error but shouldn't: () => void[], SomeClass[], and {one: 1}[].
105-
106-
* Type 2 of the following doesn't throw an error but should: {one: 1}, new() => SomeClass, SomeClass.
107-
98+
/*
99+
100+
This behaves unexpectedly with the following types:
101+
102+
Type 1 of any[]:
103+
104+
* Type 2 of the following throws an error but shouldn't: () => void[], SomeClass[], and {one: 1}[].
105+
106+
* Type 2 of the following doesn't throw an error but should: {one: 1}, new() => SomeClass, SomeClass.
107+
108108
*/
109109
var a1 = null;
110110
var c1 = new C1();

tests/baselines/reference/arrayAssignmentTest4.js

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,16 @@ var C3 = (function () {
3535
};
3636
return C3;
3737
})();
38-
/*
39-
40-
This behaves unexpectedly with teh following types:
41-
42-
Type 1 of any[]:
43-
44-
* Type 2 of the following throws an error but shouldn't: () => void[], SomeClass[], and {one: 1}[].
45-
46-
* Type 2 of the following doesn't throw an error but should: {one: 1}, new() => SomeClass, SomeClass.
47-
38+
/*
39+
40+
This behaves unexpectedly with teh following types:
41+
42+
Type 1 of any[]:
43+
44+
* Type 2 of the following throws an error but shouldn't: () => void[], SomeClass[], and {one: 1}[].
45+
46+
* Type 2 of the following doesn't throw an error but should: {one: 1}, new() => SomeClass, SomeClass.
47+
4848
*/
4949
var c3 = new C3();
5050
var o1 = { one: 1 };

tests/baselines/reference/commentBeforeStaticMethod1.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ class C {
1212
var C = (function () {
1313
function C() {
1414
}
15-
/**
16-
* Returns bar
17-
*/
15+
/**
16+
* Returns bar
17+
*/
1818
C.foo = function () {
1919
return "bar";
2020
};

tests/baselines/reference/commentOnClassMethod1.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ class WebControls {
1111
var WebControls = (function () {
1212
function WebControls() {
1313
}
14-
/**
15-
* Render a control
14+
/**
15+
* Render a control
1616
*/
1717
WebControls.prototype.createControl = function () {
1818
};

0 commit comments

Comments
 (0)