Skip to content

Port formatting related issues from master #4631

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 5 commits into from
Sep 3, 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
13 changes: 9 additions & 4 deletions src/services/formatting/rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,11 +227,13 @@ namespace ts.formatting {
public SpaceBetweenTagAndTemplateString: Rule;
public NoSpaceBetweenTagAndTemplateString: Rule;

// Union type
// Type operation
public SpaceBeforeBar: Rule;
public NoSpaceBeforeBar: Rule;
public SpaceAfterBar: Rule;
public NoSpaceAfterBar: Rule;
public SpaceBeforeAmpersand: Rule;
public SpaceAfterAmpersand: Rule;

constructor() {
///
Expand Down Expand Up @@ -272,7 +274,7 @@ namespace ts.formatting {
this.SpaceBeforeOpenBraceInFunction = new Rule(RuleDescriptor.create2(this.FunctionOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext, Rules.IsBeforeBlockContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeMultilineBlockContext), RuleAction.Space), RuleFlags.CanDeleteNewLines);

// Place a space before open brace in a TypeScript declaration that has braces as children (class, module, enum, etc)
this.TypeScriptOpenBraceLeftTokenRange = Shared.TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.MultiLineCommentTrivia]);
this.TypeScriptOpenBraceLeftTokenRange = Shared.TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.MultiLineCommentTrivia, SyntaxKind.ClassKeyword]);
this.SpaceBeforeOpenBraceInTypeScriptDeclWithBlock = new Rule(RuleDescriptor.create2(this.TypeScriptOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsTypeScriptDeclWithBlockContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeMultilineBlockContext), RuleAction.Space), RuleFlags.CanDeleteNewLines);

// Place a space before open brace in a control flow construct
Expand Down Expand Up @@ -394,12 +396,13 @@ namespace ts.formatting {
this.SpaceBetweenTagAndTemplateString = new Rule(RuleDescriptor.create3(SyntaxKind.Identifier, Shared.TokenRange.FromTokens([SyntaxKind.NoSubstitutionTemplateLiteral, SyntaxKind.TemplateHead])), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space));
this.NoSpaceBetweenTagAndTemplateString = new Rule(RuleDescriptor.create3(SyntaxKind.Identifier, Shared.TokenRange.FromTokens([SyntaxKind.NoSubstitutionTemplateLiteral, SyntaxKind.TemplateHead])), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));

// union type
// type operation
this.SpaceBeforeBar = new Rule(RuleDescriptor.create3(SyntaxKind.BarToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space));
this.NoSpaceBeforeBar = new Rule(RuleDescriptor.create3(SyntaxKind.BarToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
this.SpaceAfterBar = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.BarToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space));
this.NoSpaceAfterBar = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.BarToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));

this.SpaceBeforeAmpersand = new Rule(RuleDescriptor.create3(SyntaxKind.AmpersandToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space));
this.SpaceAfterAmpersand = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.AmpersandToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space));

// These rules are higher in priority than user-configurable rules.
this.HighPriorityCommonRules =
Expand Down Expand Up @@ -432,6 +435,7 @@ namespace ts.formatting {
this.SpaceAfterTypeKeyword, this.NoSpaceAfterTypeKeyword,
this.SpaceBetweenTagAndTemplateString, this.NoSpaceBetweenTagAndTemplateString,
this.SpaceBeforeBar, this.NoSpaceBeforeBar, this.SpaceAfterBar, this.NoSpaceAfterBar,
this.SpaceBeforeAmpersand, this.SpaceAfterAmpersand,

// TypeScript-specific rules
this.NoSpaceAfterConstructor, this.NoSpaceAfterModuleImport,
Expand Down Expand Up @@ -663,6 +667,7 @@ namespace ts.formatting {
static NodeIsTypeScriptDeclWithBlockContext(node: Node): boolean {
switch (node.kind) {
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ClassExpression:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.TypeLiteral:
Expand Down
2 changes: 1 addition & 1 deletion src/services/formatting/smartIndenter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,7 @@ namespace ts.formatting {
function nodeContentIsAlwaysIndented(kind: SyntaxKind): boolean {
switch (kind) {
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ClassExpression:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.TypeAliasDeclaration:
Expand Down Expand Up @@ -436,7 +437,6 @@ namespace ts.formatting {
case SyntaxKind.Parameter:
case SyntaxKind.FunctionType:
case SyntaxKind.ConstructorType:
case SyntaxKind.UnionType:
case SyntaxKind.ParenthesizedType:
case SyntaxKind.TaggedTemplateExpression:
case SyntaxKind.AwaitExpression:
Expand Down
2 changes: 1 addition & 1 deletion src/services/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1866,7 +1866,7 @@ namespace ts {
let sourceMapText: string;
// Create a compilerHost object to allow the compiler to read and write files
let compilerHost: CompilerHost = {
getSourceFile: (fileName, target) => fileName === inputFileName ? sourceFile : undefined,
getSourceFile: (fileName, target) => fileName === normalizeSlashes(inputFileName) ? sourceFile : undefined,
writeFile: (name, text, writeByteOrderMark) => {
if (fileExtensionIs(name, ".map")) {
Debug.assert(sourceMapText === undefined, `Unexpected multiple source map outputs for the file '${name}'`);
Expand Down
39 changes: 25 additions & 14 deletions src/services/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ namespace ts {
return find(startNode || sourceFile);

function findRightmostToken(n: Node): Node {
if (isToken(n)) {
if (isToken(n) || n.kind === SyntaxKind.JsxText) {
return n;
}

Expand All @@ -371,24 +371,35 @@ namespace ts {
}

function find(n: Node): Node {
if (isToken(n)) {
if (isToken(n) || n.kind === SyntaxKind.JsxText) {
return n;
}

let children = n.getChildren();
const children = n.getChildren();
for (let i = 0, len = children.length; i < len; i++) {
let child = children[i];
if (nodeHasTokens(child)) {
if (position <= child.end) {
if (child.getStart(sourceFile) >= position) {
// actual start of the node is past the position - previous token should be at the end of previous child
let candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ i);
return candidate && findRightmostToken(candidate)
}
else {
// candidate should be in this node
return find(child);
}
// condition 'position < child.end' checks if child node end after the position
// in the example below this condition will be false for 'aaaa' and 'bbbb' and true for 'ccc'
// aaaa___bbbb___$__ccc
// after we found child node with end after the position we check if start of the node is after the position.
// if yes - then position is in the trivia and we need to look into the previous child to find the token in question.
// if no - position is in the node itself so we should recurse in it.
// NOTE: JsxText is a weird kind of node that can contain only whitespaces (since they are not counted as trivia).
// if this is the case - then we should assume that token in question is located in previous child.
if (position < child.end && (nodeHasTokens(child) || child.kind === SyntaxKind.JsxText)) {
const start = child.getStart(sourceFile);
const lookInPreviousChild =
(start >= position) || // cursor in the leading trivia
(child.kind === SyntaxKind.JsxText && start === child.end); // whitespace only JsxText

if (lookInPreviousChild) {
// actual start of the node is past the position - previous token should be at the end of previous child
let candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ i);
return candidate && findRightmostToken(candidate)
}
else {
// candidate should be in this node
return find(child);
}
}
}
Expand Down
23 changes: 23 additions & 0 deletions tests/cases/fourslash/formatClassExpression.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/// <reference path="fourslash.ts"/>

////class Thing extends (
//// class/*classOpenBrace*/
//// {
/////*classIndent*/
//// protected doThing() {/*methodAutoformat*/
/////*methodIndent*/
//// }
//// }
////) {
////}

format.document();

goTo.marker("classOpenBrace");
verify.currentLineContentIs(" class {");
goTo.marker("classIndent");
verify.indentationIs(8);
goTo.marker("methodAutoformat");
verify.currentLineContentIs(" protected doThing() {");
goTo.marker("methodIndent");
verify.indentationIs(12);
26 changes: 26 additions & 0 deletions tests/cases/fourslash/formatTypeOperation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/// <reference path="fourslash.ts"/>

////type Union = number | {}/*formatBarOperator*/
/////*indent*/
////|string/*autoformat*/
////type Intersection = Foo & Bar;/*formatAmpersandOperator*/
////type Complexed =
//// Foo&
//// Bar|/*unionTypeNoIndent*/
//// Baz;/*intersectionTypeNoIndent*/

format.document();

goTo.marker("formatBarOperator");
verify.currentLineContentIs("type Union = number | {}");
goTo.marker("indent");
verify.indentationIs(4);
goTo.marker("autoformat");
verify.currentLineContentIs(" | string");
goTo.marker("formatAmpersandOperator");
verify.currentLineContentIs("type Intersection = Foo & Bar;");

goTo.marker("unionTypeNoIndent");
verify.currentLineContentIs(" Bar |");
goTo.marker("intersectionTypeNoIndent");
verify.currentLineContentIs(" Baz;");
14 changes: 0 additions & 14 deletions tests/cases/fourslash/formatTypeUnion.ts

This file was deleted.

17 changes: 17 additions & 0 deletions tests/cases/fourslash/indentationInJsx1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/// <reference path='fourslash.ts' />

//@Filename: file.tsx
////(function () {
//// return (
//// <div>
//// <div>
//// </div>
//// /*indent2*/
//// </div>
//// )
////})


format.document();
goTo.marker("indent2");
verify.indentationIs(12);
7 changes: 7 additions & 0 deletions tests/cases/fourslash/indentationInJsx2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/// <reference path="fourslash.ts"/>

//@Filename: file.tsx
////<div>/*1*/
goTo.marker("1");
edit.insert("\n");
verify.indentationIs(0);
8 changes: 6 additions & 2 deletions tests/cases/unittests/transpile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ module ts {
let transpileModuleResultWithSourceMap = transpileModule(input, transpileOptions);
assert.isTrue(transpileModuleResultWithSourceMap.sourceMapText !== undefined);

let expectedSourceMapFileName = removeFileExtension(transpileOptions.fileName) + ".js.map";
let expectedSourceMappingUrlLine = `//# sourceMappingURL=${expectedSourceMapFileName}`;
let expectedSourceMapFileName = removeFileExtension(getBaseFileName(normalizeSlashes(transpileOptions.fileName))) + ".js.map";
let expectedSourceMappingUrlLine = `//# sourceMappingURL=${expectedSourceMapFileName}`;

if (testSettings.expectedOutput !== undefined) {
assert.equal(transpileModuleResultWithSourceMap.outputText, testSettings.expectedOutput + expectedSourceMappingUrlLine);
Expand Down Expand Up @@ -270,5 +270,9 @@ var x = 0;`,
expectedOutput: output
});
});

it("Supports backslashes in file name", () => {
test("var x", { expectedOutput: "var x;\r\n", options: { fileName: "a\\b.ts" }});
});
});
}