Skip to content

Commit e76d8f3

Browse files
committed
Align the multiline comments in the generated outputs by retaining its position relative to the first line in the comment
1 parent 0caa1f6 commit e76d8f3

37 files changed

+650
-209
lines changed

src/compiler/emitter.ts

Lines changed: 140 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,18 @@ module ts {
1010
getLine(): number;
1111
getColumn(): number;
1212
getIndent(): number;
13-
isLineStart(): boolean;
1413
}
1514

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

2127
export function emitFiles(resolver: EmitResolver): EmitResult {
@@ -148,7 +154,6 @@ module ts {
148154
getLine: () => lineCount + 1,
149155
getColumn: () => lineStart ? indent * 4 + 1 : output.length - linePos + 1,
150156
getText: () => output,
151-
isLineStart: () => lineStart
152157
};
153158
}
154159

@@ -179,7 +184,137 @@ module ts {
179184
}
180185

181186
function writeCommentRange(comment: Comment, writer: EmitTextWriter) {
182-
writer.writeLiteral(currentSourceFile.text.substring(comment.pos, comment.end));
187+
if (currentSourceFile.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk) {
188+
var firstCommentLineAndCharacter = currentSourceFile.getLineAndCharacterFromPosition(comment.pos);
189+
var firstCommentLineIndent: number;
190+
var writeNewLine: boolean;
191+
for (var pos = comment.pos, currentLine = firstCommentLineAndCharacter.line; pos < comment.end; currentLine++) {
192+
var nextLineStart = currentSourceFile.getPositionFromLineAndCharacter(currentLine + 1, /*character*/1);
193+
194+
if (pos !== comment.pos) {
195+
// If we are not emitting first line, we need to adjust the indent
196+
if (writeNewLine) {
197+
writer.writeLine();
198+
}
199+
200+
if (firstCommentLineIndent === undefined) {
201+
firstCommentLineIndent = calculateIndent(currentSourceFile.getPositionFromLineAndCharacter(firstCommentLineAndCharacter.line, /*character*/1),
202+
comment.pos);
203+
}
204+
var deltaIndent = calculateIndent(pos, nextLineStart) - firstCommentLineIndent;
205+
if (deltaIndent < 0) {
206+
// we need to decrease indent to get the desired effect
207+
// Comment is left indented to first line
208+
// eg
209+
// module m {
210+
// /* this is line 1
211+
// * line
212+
// More left indented comment */
213+
// class c { }
214+
// }
215+
216+
// Spaces to emit = indentSize - (numberof spaces in lastDeltaIndent) (in above eg (4 - 5%4) = 3)
217+
var spacesToEmit = (deltaIndent % getIndentSize()); // This is negative of spaces to emit = -1 in above case
218+
if (spacesToEmit) {
219+
spacesToEmit += getIndentSize(); // Adjust the delta with the indentSize (4 - 1) = 3
220+
}
221+
222+
// Change in delta indent = deltaIndent / indentSize, we will change the delta to upper integer value
223+
// In above eg. 5/4 = 1.75 so change the indent two times
224+
var changeInIndent = (-deltaIndent / getIndentSize());
225+
226+
// If we cant go back as much as we want to, go to left most position
227+
if (changeInIndent > writer.getIndent()) {
228+
changeInIndent = writer.getIndent();
229+
spacesToEmit = 0;
230+
}
231+
232+
// Decrease the chaneInIndent number of times
233+
for (var i = 0; i < changeInIndent; i++) {
234+
writer.decreaseIndent();
235+
}
236+
237+
// Emit either delta spaces or indentSizeSpaces
238+
emitSpaces(spacesToEmit, writeNewLine);
239+
240+
// Write the comment line text
241+
writeNewLine = writeTrimmedCurrentLine(pos, nextLineStart);
242+
243+
// Revert the indent
244+
for (var i = 0; i < changeInIndent; i++) {
245+
writer.increaseIndent();
246+
}
247+
} else {
248+
// Comment is right indented to first line
249+
// eg
250+
// module m {
251+
// /* this is line 1
252+
// * line
253+
// More right indented comment */
254+
// class c { }
255+
// }
256+
// In above eg for line 2 in the comment, the delta is single space and hence emit that and emit the trimmed line
257+
// but the third line has delta of 7 spaces and hence emit those spaces before emitting the trimmed line
258+
emitSpaces(deltaIndent, writeNewLine);
259+
writeNewLine = writeTrimmedCurrentLine(pos, nextLineStart);
260+
}
261+
}
262+
else {
263+
// First comment line, emit as it is
264+
writeNewLine = writeTrimmedCurrentLine(pos, nextLineStart);
265+
}
266+
267+
pos = nextLineStart;
268+
}
269+
}
270+
else {
271+
// Single line comment of styly //....
272+
writer.write(currentSourceFile.text.substring(comment.pos, comment.end));
273+
}
274+
275+
function emitSpaces(count: number, writeNewLine: boolean) {
276+
if (!writeNewLine) {
277+
// If we didnot use WriteLine but instead used writeLiteral to writeNewLine, then we need to make sure we emit indent correctly
278+
writer.write(getIndentString(writer.getIndent()));
279+
}
280+
281+
// Write spaces
282+
while (count) {
283+
writer.write(" ");
284+
count--;
285+
}
286+
}
287+
288+
// Returns true if writer should write new line before emitting next line of comment
289+
function writeTrimmedCurrentLine(pos: number, nextLineStart: number) {
290+
var currentLineText = currentSourceFile.text.substring(pos, Math.min(comment.end, nextLineStart - 1)).replace(/^\s+|\s+$/g, '');
291+
if (currentLineText) {
292+
// trimmed forward and ending spaces text
293+
writer.write(currentLineText);
294+
return true;
295+
}
296+
else {
297+
// Empty string - make sure we write empty line
298+
writer.writeLiteral(sys.newLine);
299+
}
300+
}
301+
302+
function calculateIndent(pos: number, end: number) {
303+
var currentLineIndent = 0;
304+
while (pos < end && isWhiteSpace(currentSourceFile.text.charCodeAt(pos))) {
305+
pos++;
306+
if (currentSourceFile.text.charCodeAt(pos) === CharacterCodes.tab) {
307+
// Tabs = size of the indent
308+
currentLineIndent += getIndentSize();
309+
}
310+
else {
311+
// Single space
312+
currentLineIndent++;
313+
}
314+
}
315+
316+
return currentLineIndent;
317+
}
183318
}
184319

185320
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: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,10 @@ module ts {
264264
return result;
265265
}
266266

267+
export function getPositionFromLineAndCharacter(lineStarts: number[], line: number, character: number): number {
268+
return lineStarts[line - 1] + character - 1;
269+
}
270+
267271
export function getLineAndCharacterOfPosition(lineStarts: number[], position: number) {
268272
var lineNumber = binarySearch(lineStarts, position);
269273
if (lineNumber < 0) {
@@ -286,13 +290,13 @@ module ts {
286290

287291
var hasOwnProperty = Object.prototype.hasOwnProperty;
288292

289-
function isWhiteSpace(ch: number): boolean {
293+
export function isWhiteSpace(ch: number): boolean {
290294
return ch === CharacterCodes.space || ch === CharacterCodes.tab || ch === CharacterCodes.verticalTab || ch === CharacterCodes.formFeed ||
291295
ch === CharacterCodes.nonBreakingSpace || ch === CharacterCodes.ogham || ch >= CharacterCodes.enQuad && ch <= CharacterCodes.zeroWidthSpace ||
292296
ch === CharacterCodes.narrowNoBreakSpace || ch === CharacterCodes.mathematicalSpace || ch === CharacterCodes.ideographicSpace || ch === CharacterCodes.byteOrderMark;
293297
}
294298

295-
function isLineBreak(ch: number): boolean {
299+
export function isLineBreak(ch: number): boolean {
296300
return ch === CharacterCodes.lineFeed || ch === CharacterCodes.carriageReturn || ch === CharacterCodes.lineSeparator || ch === CharacterCodes.paragraphSeparator;
297301
}
298302

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)