From 7bf73be7fe58686309416e817614e5ccf4581e03 Mon Sep 17 00:00:00 2001 From: Andrew Ochsner Date: Mon, 19 Dec 2016 23:05:30 -0600 Subject: [PATCH 1/2] space-before-function-paren Adding option InsertSpaceBeforeFunctionParenthesis Should be optional Typically used to support http://eslint.org/docs/rules/space-before-function-paren Fixes #12234 --- src/server/protocol.ts | 1 + src/server/utilities.ts | 1 + src/services/formatting/rules.ts | 3 ++- src/services/formatting/rulesProvider.ts | 7 +++++++ src/services/types.ts | 2 ++ .../fourslash/formattingSpaceBeforeFunctionParen.ts | 13 +++++++++++++ 6 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 tests/cases/fourslash/formattingSpaceBeforeFunctionParen.ts diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 39012e49fcddb..f38862befcefd 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -2200,6 +2200,7 @@ namespace ts.server.protocol { insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets?: boolean; insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces?: boolean; insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces?: boolean; + insertSpaceBeforeFunctionParenthesis?: boolean; placeOpenBraceOnNewLineForFunctions?: boolean; placeOpenBraceOnNewLineForControlBlocks?: boolean; } diff --git a/src/server/utilities.ts b/src/server/utilities.ts index 839e79268fad8..f15a494b5c4b2 100644 --- a/src/server/utilities.ts +++ b/src/server/utilities.ts @@ -87,6 +87,7 @@ namespace ts.server { insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false, insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false, insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false, + insertSpaceBeforeFunctionParenthesis: false, placeOpenBraceOnNewLineForFunctions: false, placeOpenBraceOnNewLineForControlBlocks: false, }; diff --git a/src/services/formatting/rules.ts b/src/services/formatting/rules.ts index 2095f062bd103..869f84d265315 100644 --- a/src/services/formatting/rules.ts +++ b/src/services/formatting/rules.ts @@ -87,6 +87,7 @@ namespace ts.formatting { public SpaceAfterLetConstInVariableDeclaration: Rule; public NoSpaceBeforeOpenParenInFuncCall: Rule; public SpaceAfterFunctionInFuncDecl: Rule; + public SpaceBeforeOpenParenInFuncDecl: Rule; public NoSpaceBeforeOpenParenInFuncDecl: Rule; public SpaceAfterVoidOperator: Rule; @@ -329,6 +330,7 @@ namespace ts.formatting { this.SpaceAfterLetConstInVariableDeclaration = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.LetKeyword, SyntaxKind.ConstKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsStartOfVariableDeclarationList), RuleAction.Space)); this.NoSpaceBeforeOpenParenInFuncCall = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsFunctionCallOrNewContext, Rules.IsPreviousTokenNotComma), RuleAction.Delete)); this.SpaceAfterFunctionInFuncDecl = new Rule(RuleDescriptor.create3(SyntaxKind.FunctionKeyword, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Space)); + this.SpaceBeforeOpenParenInFuncDecl = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsFunctionDeclContext), RuleAction.Space)); this.NoSpaceBeforeOpenParenInFuncDecl = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsFunctionDeclContext), RuleAction.Delete)); this.SpaceAfterVoidOperator = new Rule(RuleDescriptor.create3(SyntaxKind.VoidKeyword, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsVoidOpContext), RuleAction.Space)); @@ -462,7 +464,6 @@ namespace ts.formatting { this.NoSpaceBeforeOpenBracket, this.NoSpaceAfterCloseBracket, this.SpaceAfterSemicolon, - this.NoSpaceBeforeOpenParenInFuncDecl, this.SpaceBetweenStatements, this.SpaceAfterTryFinally ]; diff --git a/src/services/formatting/rulesProvider.ts b/src/services/formatting/rulesProvider.ts index 4a2c9d0f15586..f999b780e8782 100644 --- a/src/services/formatting/rulesProvider.ts +++ b/src/services/formatting/rulesProvider.ts @@ -128,6 +128,13 @@ namespace ts.formatting { rules.push(this.globalRules.NoSpaceAfterBinaryOperator); } + if (options.insertSpaceBeforeFunctionParenthesis) { + rules.push(this.globalRules.SpaceBeforeOpenParenInFuncDecl); + } + else { + rules.push(this.globalRules.NoSpaceBeforeOpenParenInFuncDecl); + } + if (options.placeOpenBraceOnNewLineForControlBlocks) { rules.push(this.globalRules.NewLineBeforeOpenBraceInControl); } diff --git a/src/services/types.ts b/src/services/types.ts index 3865fe7fac94c..ac7d422a299f7 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -426,6 +426,7 @@ namespace ts { InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: boolean; InsertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces?: boolean; InsertSpaceAfterTypeAssertion?: boolean; + InsertSpaceBeforeFunctionParenthesis?: boolean; PlaceOpenBraceOnNewLineForFunctions: boolean; PlaceOpenBraceOnNewLineForControlBlocks: boolean; } @@ -442,6 +443,7 @@ namespace ts { insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces?: boolean; insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces?: boolean; insertSpaceAfterTypeAssertion?: boolean; + insertSpaceBeforeFunctionParenthesis?: boolean; placeOpenBraceOnNewLineForFunctions?: boolean; placeOpenBraceOnNewLineForControlBlocks?: boolean; } diff --git a/tests/cases/fourslash/formattingSpaceBeforeFunctionParen.ts b/tests/cases/fourslash/formattingSpaceBeforeFunctionParen.ts new file mode 100644 index 0000000000000..4b21a3f038954 --- /dev/null +++ b/tests/cases/fourslash/formattingSpaceBeforeFunctionParen.ts @@ -0,0 +1,13 @@ +/// + +/////*1*/function foo() { } +/////*2*/function boo () { } + +format.setOption("InsertSpaceBeforeFunctionParenthesis", true); + +format.document(); + +goTo.marker('1'); +verify.currentLineContentIs('function foo () { }'); +goTo.marker('2'); +verify.currentLineContentIs('function boo () { }'); \ No newline at end of file From 3b3d71542c045f5f8228f8c795ff2a18db36df66 Mon Sep 17 00:00:00 2001 From: Andrew Ochsner Date: Tue, 20 Dec 2016 10:05:10 -0600 Subject: [PATCH 2/2] Add InsertSpaceAfterConstructor option & additonal test cases Fixes #12234 --- src/harness/fourslash.ts | 1 + src/server/protocol.ts | 1 + src/server/utilities.ts | 1 + src/services/formatting/rules.ts | 4 +++- src/services/formatting/rulesProvider.ts | 7 +++++++ src/services/types.ts | 2 ++ .../fourslash/formattingSpaceBeforeFunctionParen.ts | 8 +++++++- .../cases/fourslash/formattingSpacesAfterConstructor.ts | 9 ++++++++- 8 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 7c7a06db0b6c9..653b87236fd73 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -341,6 +341,7 @@ namespace FourSlash { insertSpaceAfterCommaDelimiter: true, insertSpaceAfterSemicolonInForStatements: true, insertSpaceBeforeAndAfterBinaryOperators: true, + insertSpaceAfterConstructor: false, insertSpaceAfterKeywordsInControlFlowStatements: true, insertSpaceAfterFunctionKeywordForAnonymousFunctions: false, insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false, diff --git a/src/server/protocol.ts b/src/server/protocol.ts index f38862befcefd..680b81dff9986 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -2194,6 +2194,7 @@ namespace ts.server.protocol { insertSpaceAfterCommaDelimiter?: boolean; insertSpaceAfterSemicolonInForStatements?: boolean; insertSpaceBeforeAndAfterBinaryOperators?: boolean; + insertSpaceAfterConstructor?: boolean; insertSpaceAfterKeywordsInControlFlowStatements?: boolean; insertSpaceAfterFunctionKeywordForAnonymousFunctions?: boolean; insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis?: boolean; diff --git a/src/server/utilities.ts b/src/server/utilities.ts index f15a494b5c4b2..641ca128e634d 100644 --- a/src/server/utilities.ts +++ b/src/server/utilities.ts @@ -78,6 +78,7 @@ namespace ts.server { newLineCharacter: host.newLine || "\n", convertTabsToSpaces: true, indentStyle: ts.IndentStyle.Smart, + insertSpaceAfterConstructor: false, insertSpaceAfterCommaDelimiter: true, insertSpaceAfterSemicolonInForStatements: true, insertSpaceBeforeAndAfterBinaryOperators: true, diff --git a/src/services/formatting/rules.ts b/src/services/formatting/rules.ts index 869f84d265315..be592174d2e2f 100644 --- a/src/services/formatting/rules.ts +++ b/src/services/formatting/rules.ts @@ -113,6 +113,7 @@ namespace ts.formatting { // TypeScript-specific rules // Treat constructor as an identifier in a function declaration, and remove spaces between constructor and following left parentheses + public SpaceAfterConstructor: Rule; public NoSpaceAfterConstructor: Rule; // Use of module as a function call. e.g.: import m2 = module("m2"); @@ -354,6 +355,7 @@ namespace ts.formatting { // TypeScript-specific higher priority rules // Treat constructor as an identifier in a function declaration, and remove spaces between constructor and following left parentheses + this.SpaceAfterConstructor = new Rule(RuleDescriptor.create1(SyntaxKind.ConstructorKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space)); this.NoSpaceAfterConstructor = new Rule(RuleDescriptor.create1(SyntaxKind.ConstructorKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); // Use of module as a function call. e.g.: import m2 = module("m2"); @@ -439,7 +441,7 @@ namespace ts.formatting { this.NoSpaceBeforeEqualInJsxAttribute, this.NoSpaceAfterEqualInJsxAttribute, // TypeScript-specific rules - this.NoSpaceAfterConstructor, this.NoSpaceAfterModuleImport, + this.NoSpaceAfterModuleImport, this.SpaceAfterCertainTypeScriptKeywords, this.SpaceBeforeCertainTypeScriptKeywords, this.SpaceAfterModuleName, this.SpaceBeforeArrow, this.SpaceAfterArrow, diff --git a/src/services/formatting/rulesProvider.ts b/src/services/formatting/rulesProvider.ts index f999b780e8782..14e08e4857aee 100644 --- a/src/services/formatting/rulesProvider.ts +++ b/src/services/formatting/rulesProvider.ts @@ -38,6 +38,13 @@ namespace ts.formatting { private createActiveRules(options: ts.FormatCodeSettings): Rule[] { let rules = this.globalRules.HighPriorityCommonRules.slice(0); + if (options.insertSpaceAfterConstructor) { + rules.push(this.globalRules.SpaceAfterConstructor); + } + else { + rules.push(this.globalRules.NoSpaceAfterConstructor); + } + if (options.insertSpaceAfterCommaDelimiter) { rules.push(this.globalRules.SpaceAfterComma); } diff --git a/src/services/types.ts b/src/services/types.ts index ac7d422a299f7..88ffe2950ced8 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -418,6 +418,7 @@ namespace ts { InsertSpaceAfterCommaDelimiter: boolean; InsertSpaceAfterSemicolonInForStatements: boolean; InsertSpaceBeforeAndAfterBinaryOperators: boolean; + InsertSpaceAfterConstructor?: boolean; InsertSpaceAfterKeywordsInControlFlowStatements: boolean; InsertSpaceAfterFunctionKeywordForAnonymousFunctions: boolean; InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: boolean; @@ -435,6 +436,7 @@ namespace ts { insertSpaceAfterCommaDelimiter?: boolean; insertSpaceAfterSemicolonInForStatements?: boolean; insertSpaceBeforeAndAfterBinaryOperators?: boolean; + insertSpaceAfterConstructor?: boolean; insertSpaceAfterKeywordsInControlFlowStatements?: boolean; insertSpaceAfterFunctionKeywordForAnonymousFunctions?: boolean; insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis?: boolean; diff --git a/tests/cases/fourslash/formattingSpaceBeforeFunctionParen.ts b/tests/cases/fourslash/formattingSpaceBeforeFunctionParen.ts index 4b21a3f038954..ce85521879ed3 100644 --- a/tests/cases/fourslash/formattingSpaceBeforeFunctionParen.ts +++ b/tests/cases/fourslash/formattingSpaceBeforeFunctionParen.ts @@ -2,6 +2,8 @@ /////*1*/function foo() { } /////*2*/function boo () { } +/////*3*/var bar = function foo() { }; +/////*4*/var foo = { bar() { } }; format.setOption("InsertSpaceBeforeFunctionParenthesis", true); @@ -10,4 +12,8 @@ format.document(); goTo.marker('1'); verify.currentLineContentIs('function foo () { }'); goTo.marker('2'); -verify.currentLineContentIs('function boo () { }'); \ No newline at end of file +verify.currentLineContentIs('function boo () { }'); +goTo.marker('3'); +verify.currentLineContentIs('var bar = function foo () { };'); +goTo.marker('4'); +verify.currentLineContentIs('var foo = { bar () { } };'); \ No newline at end of file diff --git a/tests/cases/fourslash/formattingSpacesAfterConstructor.ts b/tests/cases/fourslash/formattingSpacesAfterConstructor.ts index 8df762def20a1..2195d74adbc1d 100644 --- a/tests/cases/fourslash/formattingSpacesAfterConstructor.ts +++ b/tests/cases/fourslash/formattingSpacesAfterConstructor.ts @@ -3,4 +3,11 @@ /////*1*/class test { constructor () { } } format.document(); goTo.marker("1"); -verify.currentLineContentIs("class test { constructor() { } }"); \ No newline at end of file +verify.currentLineContentIs("class test { constructor() { } }"); + +/////*2*/class test { constructor () { } } +format.setOption("InsertSpaceAfterConstructor", true); + +format.document(); +goTo.marker("2"); +verify.currentLineContentIs("class test { constructor () { } }"); \ No newline at end of file