From 1d0bde04761548d068c6dfb667d2a28d1607b1b5 Mon Sep 17 00:00:00 2001 From: Basarat Ali Syed Date: Wed, 13 May 2015 09:17:39 +1000 Subject: [PATCH 1/9] :memo: document autocrlf needs to be off otherwise people will get test failures which are not immediately obvious --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ac00ef085bc..7d9a430a914 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ There are many ways to [contribute](https://github.com/Microsoft/TypeScript/blob ## Building -In order to build the TypeScript compiler, ensure that you have [Git](http://git-scm.com/downloads) and [Node.js](http://nodejs.org/) installed. +In order to build the TypeScript compiler, ensure that you have [Git](http://git-scm.com/downloads) and [Node.js](http://nodejs.org/) installed. Note that you need to have autocrlf off as we track whitespace changes (`git config --global core.autocrlf false`). Clone a copy of the repo: From d080f47003ee31bd183a583e95f0e1abb2a54b98 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Tue, 19 May 2015 16:17:12 -0700 Subject: [PATCH 2/9] Fix for #2971, adds missing logic in checkFunctionExpressionBodies --- src/compiler/checker.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3b7e787fe4b..9bd0d6475fe 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6605,7 +6605,7 @@ module ts { result.splice(spliceIndex, 0, signature); } } - + function getSpreadArgumentIndex(args: Expression[]): number { for (let i = 0; i < args.length; i++) { if (args[i].kind === SyntaxKind.SpreadElementExpression) { @@ -10914,6 +10914,7 @@ module ts { break; case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: + forEach(node.decorators, checkFunctionExpressionBodies); forEach((node).parameters, checkFunctionExpressionBodies); if (isObjectLiteralMethod(node)) { checkFunctionExpressionOrObjectLiteralMethodBody(node); @@ -10928,6 +10929,7 @@ module ts { case SyntaxKind.WithStatement: checkFunctionExpressionBodies((node).expression); break; + case SyntaxKind.Decorator: case SyntaxKind.Parameter: case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: From 4b031ea76e5d3771771d63a3f6f91e43b53c6dda Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Tue, 19 May 2015 22:07:45 -0700 Subject: [PATCH 3/9] Added tests --- .../decoratorChecksFunctionBodies.errors.txt | 21 ++++++++ .../decoratorChecksFunctionBodies.js | 44 +++++++++++++++ ...ratorInstantiateModulesInFunctionBodies.js | 53 +++++++++++++++++++ ...InstantiateModulesInFunctionBodies.symbols | 34 ++++++++++++ ...orInstantiateModulesInFunctionBodies.types | 40 ++++++++++++++ .../class/decoratorChecksFunctionBodies.ts | 16 ++++++ ...ratorInstantiateModulesInFunctionBodies.ts | 22 ++++++++ 7 files changed, 230 insertions(+) create mode 100644 tests/baselines/reference/decoratorChecksFunctionBodies.errors.txt create mode 100644 tests/baselines/reference/decoratorChecksFunctionBodies.js create mode 100644 tests/baselines/reference/decoratorInstantiateModulesInFunctionBodies.js create mode 100644 tests/baselines/reference/decoratorInstantiateModulesInFunctionBodies.symbols create mode 100644 tests/baselines/reference/decoratorInstantiateModulesInFunctionBodies.types create mode 100644 tests/cases/conformance/decorators/class/decoratorChecksFunctionBodies.ts create mode 100644 tests/cases/conformance/decorators/class/decoratorInstantiateModulesInFunctionBodies.ts diff --git a/tests/baselines/reference/decoratorChecksFunctionBodies.errors.txt b/tests/baselines/reference/decoratorChecksFunctionBodies.errors.txt new file mode 100644 index 00000000000..c8166b538fd --- /dev/null +++ b/tests/baselines/reference/decoratorChecksFunctionBodies.errors.txt @@ -0,0 +1,21 @@ +tests/cases/conformance/decorators/class/decoratorChecksFunctionBodies.ts(9,14): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. + + +==== tests/cases/conformance/decorators/class/decoratorChecksFunctionBodies.ts (1 errors) ==== + + // from #2971 + function func(s: string): void { + } + + class A { + @(x => { + var a = 3; + func(a); + ~ +!!! error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. + return x; + }) + m() { + + } + } \ No newline at end of file diff --git a/tests/baselines/reference/decoratorChecksFunctionBodies.js b/tests/baselines/reference/decoratorChecksFunctionBodies.js new file mode 100644 index 00000000000..020bc775aea --- /dev/null +++ b/tests/baselines/reference/decoratorChecksFunctionBodies.js @@ -0,0 +1,44 @@ +//// [decoratorChecksFunctionBodies.ts] + +// from #2971 +function func(s: string): void { +} + +class A { + @(x => { + var a = 3; + func(a); + return x; + }) + m() { + + } +} + +//// [decoratorChecksFunctionBodies.js] +var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc); + switch (arguments.length) { + case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target); + case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0); + case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc); + } +}; +// from #2971 +function func(s) { +} +var A = (function () { + function A() { + } + A.prototype.m = function () { + }; + Object.defineProperty(A.prototype, "m", + __decorate([ + (function (x) { + var a = 3; + func(a); + return x; + }) + ], A.prototype, "m", Object.getOwnPropertyDescriptor(A.prototype, "m"))); + return A; +})(); diff --git a/tests/baselines/reference/decoratorInstantiateModulesInFunctionBodies.js b/tests/baselines/reference/decoratorInstantiateModulesInFunctionBodies.js new file mode 100644 index 00000000000..313d77fa5ce --- /dev/null +++ b/tests/baselines/reference/decoratorInstantiateModulesInFunctionBodies.js @@ -0,0 +1,53 @@ +//// [tests/cases/conformance/decorators/class/decoratorInstantiateModulesInFunctionBodies.ts] //// + +//// [a.ts] + +// from #3108 +export var test = 'abc'; + +//// [b.ts] +import { test } from './a'; + +function filter(handler: any) { + return function (target: any) { + // ... + }; +} + +class Wat { + @filter(() => test == 'abc') + static whatever() { + // ... + } +} + +//// [a.js] +// from #3108 +exports.test = 'abc'; +//// [b.js] +var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") return Reflect.decorate(decorators, target, key, desc); + switch (arguments.length) { + case 2: return decorators.reduceRight(function(o, d) { return (d && d(o)) || o; }, target); + case 3: return decorators.reduceRight(function(o, d) { return (d && d(target, key)), void 0; }, void 0); + case 4: return decorators.reduceRight(function(o, d) { return (d && d(target, key, o)) || o; }, desc); + } +}; +var a_1 = require('./a'); +function filter(handler) { + return function (target) { + // ... + }; +} +var Wat = (function () { + function Wat() { + } + Wat.whatever = function () { + // ... + }; + Object.defineProperty(Wat, "whatever", + __decorate([ + filter(function () { return a_1.test == 'abc'; }) + ], Wat, "whatever", Object.getOwnPropertyDescriptor(Wat, "whatever"))); + return Wat; +})(); diff --git a/tests/baselines/reference/decoratorInstantiateModulesInFunctionBodies.symbols b/tests/baselines/reference/decoratorInstantiateModulesInFunctionBodies.symbols new file mode 100644 index 00000000000..5088e740a57 --- /dev/null +++ b/tests/baselines/reference/decoratorInstantiateModulesInFunctionBodies.symbols @@ -0,0 +1,34 @@ +=== tests/cases/conformance/decorators/class/a.ts === + +// from #3108 +export var test = 'abc'; +>test : Symbol(test, Decl(a.ts, 2, 10)) + +=== tests/cases/conformance/decorators/class/b.ts === +import { test } from './a'; +>test : Symbol(test, Decl(b.ts, 0, 8)) + +function filter(handler: any) { +>filter : Symbol(filter, Decl(b.ts, 0, 27)) +>handler : Symbol(handler, Decl(b.ts, 2, 16)) + + return function (target: any) { +>target : Symbol(target, Decl(b.ts, 3, 21)) + + // ... + }; +} + +class Wat { +>Wat : Symbol(Wat, Decl(b.ts, 6, 1)) + + @filter(() => test == 'abc') +>filter : Symbol(filter, Decl(b.ts, 0, 27)) +>test : Symbol(test, Decl(b.ts, 0, 8)) + + static whatever() { +>whatever : Symbol(Wat.whatever, Decl(b.ts, 8, 11)) + + // ... + } +} diff --git a/tests/baselines/reference/decoratorInstantiateModulesInFunctionBodies.types b/tests/baselines/reference/decoratorInstantiateModulesInFunctionBodies.types new file mode 100644 index 00000000000..18d993af9bb --- /dev/null +++ b/tests/baselines/reference/decoratorInstantiateModulesInFunctionBodies.types @@ -0,0 +1,40 @@ +=== tests/cases/conformance/decorators/class/a.ts === + +// from #3108 +export var test = 'abc'; +>test : string +>'abc' : string + +=== tests/cases/conformance/decorators/class/b.ts === +import { test } from './a'; +>test : string + +function filter(handler: any) { +>filter : (handler: any) => (target: any) => void +>handler : any + + return function (target: any) { +>function (target: any) { // ... } : (target: any) => void +>target : any + + // ... + }; +} + +class Wat { +>Wat : Wat + + @filter(() => test == 'abc') +>filter(() => test == 'abc') : (target: any) => void +>filter : (handler: any) => (target: any) => void +>() => test == 'abc' : () => boolean +>test == 'abc' : boolean +>test : string +>'abc' : string + + static whatever() { +>whatever : () => void + + // ... + } +} diff --git a/tests/cases/conformance/decorators/class/decoratorChecksFunctionBodies.ts b/tests/cases/conformance/decorators/class/decoratorChecksFunctionBodies.ts new file mode 100644 index 00000000000..31f5fe82551 --- /dev/null +++ b/tests/cases/conformance/decorators/class/decoratorChecksFunctionBodies.ts @@ -0,0 +1,16 @@ +// @target:es5 + +// from #2971 +function func(s: string): void { +} + +class A { + @(x => { + var a = 3; + func(a); + return x; + }) + m() { + + } +} \ No newline at end of file diff --git a/tests/cases/conformance/decorators/class/decoratorInstantiateModulesInFunctionBodies.ts b/tests/cases/conformance/decorators/class/decoratorInstantiateModulesInFunctionBodies.ts new file mode 100644 index 00000000000..7fa7ab8dd84 --- /dev/null +++ b/tests/cases/conformance/decorators/class/decoratorInstantiateModulesInFunctionBodies.ts @@ -0,0 +1,22 @@ +// @target:es5 +// @module:commonjs +// @filename: a.ts + +// from #3108 +export var test = 'abc'; + +// @filename: b.ts +import { test } from './a'; + +function filter(handler: any) { + return function (target: any) { + // ... + }; +} + +class Wat { + @filter(() => test == 'abc') + static whatever() { + // ... + } +} \ No newline at end of file From de8597ca8c31eec0e7c5e08bff149db8832fa978 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 20 May 2015 16:30:50 -0700 Subject: [PATCH 4/9] Add cache to instantiateType function to break cycles --- src/compiler/checker.ts | 14 ++++++++++++++ src/compiler/types.ts | 6 ++++++ 2 files changed, 20 insertions(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9bd0d6475fe..e49deba6032 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3866,6 +3866,19 @@ module ts { } function instantiateAnonymousType(type: ObjectType, mapper: TypeMapper): ObjectType { + // If this type has already been instantiated using this mapper, returned the cached result. This guards against + // infinite instantiations of cyclic types, e.g. "var x: { a: T, b: typeof x };" + if (mapper.mappings) { + for (let mapping of mapper.mappings) { + if (mapping.type === type) { + return mapping.result; + } + } + } + else { + mapper.mappings = []; + } + // Instantiate the given type using the given mapper and cache the result let result = createObjectType(TypeFlags.Anonymous, type.symbol); result.properties = instantiateList(getPropertiesOfObjectType(type), mapper, instantiateSymbol); result.members = createSymbolTable(result.properties); @@ -3875,6 +3888,7 @@ module ts { let numberIndexType = getIndexTypeOfType(type, IndexKind.Number); if (stringIndexType) result.stringIndexType = instantiateType(stringIndexType, mapper); if (numberIndexType) result.numberIndexType = instantiateType(numberIndexType, mapper); + mapper.mappings.push({ type, result }); return result; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 86e680ca8b0..0f810c9fe61 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1586,9 +1586,15 @@ module ts { Number, } + export interface TypeMapping { + type: Type; + result: Type; + } + /* @internal */ export interface TypeMapper { (t: TypeParameter): Type; + mappings?: TypeMapping[]; // Type mapping cache } /* @internal */ From c303e14b2854dc7b289f864324a46dd52eee11e3 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 20 May 2015 16:31:03 -0700 Subject: [PATCH 5/9] Adding regression test --- .../reference/cyclicTypeInstantiation.js | 36 ++++++++++++ .../reference/cyclicTypeInstantiation.symbols | 54 ++++++++++++++++++ .../reference/cyclicTypeInstantiation.types | 57 +++++++++++++++++++ .../cases/compiler/cyclicTypeInstantiation.ts | 20 +++++++ 4 files changed, 167 insertions(+) create mode 100644 tests/baselines/reference/cyclicTypeInstantiation.js create mode 100644 tests/baselines/reference/cyclicTypeInstantiation.symbols create mode 100644 tests/baselines/reference/cyclicTypeInstantiation.types create mode 100644 tests/cases/compiler/cyclicTypeInstantiation.ts diff --git a/tests/baselines/reference/cyclicTypeInstantiation.js b/tests/baselines/reference/cyclicTypeInstantiation.js new file mode 100644 index 00000000000..087eb002418 --- /dev/null +++ b/tests/baselines/reference/cyclicTypeInstantiation.js @@ -0,0 +1,36 @@ +//// [cyclicTypeInstantiation.ts] +function foo() { + var x: { + a: T; + b: typeof x; + }; + return x; +} + +function bar() { + var x: { + a: T; + b: typeof x; + }; + return x; +} + +var a = foo(); +var b = bar(); +// Relating types of a and b produces instantiations of the cyclic anonymous types in foo and bar +a = b; + + +//// [cyclicTypeInstantiation.js] +function foo() { + var x; + return x; +} +function bar() { + var x; + return x; +} +var a = foo(); +var b = bar(); +// Relating types of a and b produces instantiations of the cyclic anonymous types in foo and bar +a = b; diff --git a/tests/baselines/reference/cyclicTypeInstantiation.symbols b/tests/baselines/reference/cyclicTypeInstantiation.symbols new file mode 100644 index 00000000000..74e59da188e --- /dev/null +++ b/tests/baselines/reference/cyclicTypeInstantiation.symbols @@ -0,0 +1,54 @@ +=== tests/cases/compiler/cyclicTypeInstantiation.ts === +function foo() { +>foo : Symbol(foo, Decl(cyclicTypeInstantiation.ts, 0, 0)) +>T : Symbol(T, Decl(cyclicTypeInstantiation.ts, 0, 13)) + + var x: { +>x : Symbol(x, Decl(cyclicTypeInstantiation.ts, 1, 7)) + + a: T; +>a : Symbol(a, Decl(cyclicTypeInstantiation.ts, 1, 12)) +>T : Symbol(T, Decl(cyclicTypeInstantiation.ts, 0, 13)) + + b: typeof x; +>b : Symbol(b, Decl(cyclicTypeInstantiation.ts, 2, 13)) +>x : Symbol(x, Decl(cyclicTypeInstantiation.ts, 1, 7)) + + }; + return x; +>x : Symbol(x, Decl(cyclicTypeInstantiation.ts, 1, 7)) +} + +function bar() { +>bar : Symbol(bar, Decl(cyclicTypeInstantiation.ts, 6, 1)) +>T : Symbol(T, Decl(cyclicTypeInstantiation.ts, 8, 13)) + + var x: { +>x : Symbol(x, Decl(cyclicTypeInstantiation.ts, 9, 7)) + + a: T; +>a : Symbol(a, Decl(cyclicTypeInstantiation.ts, 9, 12)) +>T : Symbol(T, Decl(cyclicTypeInstantiation.ts, 8, 13)) + + b: typeof x; +>b : Symbol(b, Decl(cyclicTypeInstantiation.ts, 10, 13)) +>x : Symbol(x, Decl(cyclicTypeInstantiation.ts, 9, 7)) + + }; + return x; +>x : Symbol(x, Decl(cyclicTypeInstantiation.ts, 9, 7)) +} + +var a = foo(); +>a : Symbol(a, Decl(cyclicTypeInstantiation.ts, 16, 3)) +>foo : Symbol(foo, Decl(cyclicTypeInstantiation.ts, 0, 0)) + +var b = bar(); +>b : Symbol(b, Decl(cyclicTypeInstantiation.ts, 17, 3)) +>bar : Symbol(bar, Decl(cyclicTypeInstantiation.ts, 6, 1)) + +// Relating types of a and b produces instantiations of the cyclic anonymous types in foo and bar +a = b; +>a : Symbol(a, Decl(cyclicTypeInstantiation.ts, 16, 3)) +>b : Symbol(b, Decl(cyclicTypeInstantiation.ts, 17, 3)) + diff --git a/tests/baselines/reference/cyclicTypeInstantiation.types b/tests/baselines/reference/cyclicTypeInstantiation.types new file mode 100644 index 00000000000..c3a39fc90a3 --- /dev/null +++ b/tests/baselines/reference/cyclicTypeInstantiation.types @@ -0,0 +1,57 @@ +=== tests/cases/compiler/cyclicTypeInstantiation.ts === +function foo() { +>foo : () => { a: T; b: any; } +>T : T + + var x: { +>x : { a: T; b: any; } + + a: T; +>a : T +>T : T + + b: typeof x; +>b : { a: T; b: any; } +>x : { a: T; b: any; } + + }; + return x; +>x : { a: T; b: any; } +} + +function bar() { +>bar : () => { a: T; b: any; } +>T : T + + var x: { +>x : { a: T; b: any; } + + a: T; +>a : T +>T : T + + b: typeof x; +>b : { a: T; b: any; } +>x : { a: T; b: any; } + + }; + return x; +>x : { a: T; b: any; } +} + +var a = foo(); +>a : { a: string; b: any; } +>foo() : { a: string; b: any; } +>foo : () => { a: T; b: any; } + +var b = bar(); +>b : { a: string; b: any; } +>bar() : { a: string; b: any; } +>bar : () => { a: T; b: any; } + +// Relating types of a and b produces instantiations of the cyclic anonymous types in foo and bar +a = b; +>a = b : { a: string; b: any; } +>a : { a: string; b: any; } +>b : { a: string; b: any; } + diff --git a/tests/cases/compiler/cyclicTypeInstantiation.ts b/tests/cases/compiler/cyclicTypeInstantiation.ts new file mode 100644 index 00000000000..79a222df089 --- /dev/null +++ b/tests/cases/compiler/cyclicTypeInstantiation.ts @@ -0,0 +1,20 @@ +function foo() { + var x: { + a: T; + b: typeof x; + }; + return x; +} + +function bar() { + var x: { + a: T; + b: typeof x; + }; + return x; +} + +var a = foo(); +var b = bar(); +// Relating types of a and b produces instantiations of the cyclic anonymous types in foo and bar +a = b; From ebcdd85ad06503b3776135f6c50e56c7d0f8a27d Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 21 May 2015 09:18:55 -0700 Subject: [PATCH 6/9] Changing type mapping cache to be a dictionary --- src/compiler/checker.ts | 11 +++++------ src/compiler/types.ts | 7 +------ 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e49deba6032..528ee97602b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3869,14 +3869,13 @@ module ts { // If this type has already been instantiated using this mapper, returned the cached result. This guards against // infinite instantiations of cyclic types, e.g. "var x: { a: T, b: typeof x };" if (mapper.mappings) { - for (let mapping of mapper.mappings) { - if (mapping.type === type) { - return mapping.result; - } + let cached = mapper.mappings[type.id]; + if (cached) { + return cached; } } else { - mapper.mappings = []; + mapper.mappings = {}; } // Instantiate the given type using the given mapper and cache the result let result = createObjectType(TypeFlags.Anonymous, type.symbol); @@ -3888,7 +3887,7 @@ module ts { let numberIndexType = getIndexTypeOfType(type, IndexKind.Number); if (stringIndexType) result.stringIndexType = instantiateType(stringIndexType, mapper); if (numberIndexType) result.numberIndexType = instantiateType(numberIndexType, mapper); - mapper.mappings.push({ type, result }); + mapper.mappings[type.id] = result; return result; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 0f810c9fe61..c8d22b26728 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1586,15 +1586,10 @@ module ts { Number, } - export interface TypeMapping { - type: Type; - result: Type; - } - /* @internal */ export interface TypeMapper { (t: TypeParameter): Type; - mappings?: TypeMapping[]; // Type mapping cache + mappings?: Map; // Type mapping cache } /* @internal */ From 3bfc5359ad5e548c09714358aef83424b73e6089 Mon Sep 17 00:00:00 2001 From: Ivo Gabe de Wolff Date: Thu, 21 May 2015 22:02:02 +0200 Subject: [PATCH 7/9] emitWithStatement should emit a WithStatement --- src/compiler/emitter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index d8d4bf73ed6..32ebeaec08f 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -2536,7 +2536,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { write(";"); } - function emitWithStatement(node: WhileStatement) { + function emitWithStatement(node: WithStatement) { write("with ("); emit(node.expression); write(")"); From 8e2e799f95c17ccef077141b9a2c6c8605fe388e Mon Sep 17 00:00:00 2001 From: The Gitter Badger Date: Fri, 22 May 2015 18:26:48 +0000 Subject: [PATCH 8/9] Added Gitter badge --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 7d9a430a914..ee32547ca95 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,8 @@ [![Downloads](http://img.shields.io/npm/dm/TypeScript.svg)](https://npmjs.org/package/typescript) # TypeScript + +[![Join the chat at https://gitter.im/Microsoft/TypeScript](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Microsoft/TypeScript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [TypeScript](http://www.typescriptlang.org/) is a language for application-scale JavaScript. TypeScript adds optional types, classes, and modules to JavaScript. TypeScript supports tools for large-scale JavaScript applications for any browser, for any host, on any OS. TypeScript compiles to readable, standards-based JavaScript. Try it out at the [playground](http://www.typescriptlang.org/Playground), and stay up to date via [our blog](http://blogs.msdn.com/typescript) and [twitter account](https://twitter.com/typescriptlang). From f1789acb47dbbe4ee974cfcfef38644e29a26248 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Tue, 26 May 2015 16:25:09 -0700 Subject: [PATCH 9/9] remove space after close bracket only if next token does not start block in function declaration context --- src/services/formatting/rules.ts | 6 +++++- tests/cases/fourslash/formatOnEnterFunctionDeclaration.ts | 8 ++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 tests/cases/fourslash/formatOnEnterFunctionDeclaration.ts diff --git a/src/services/formatting/rules.ts b/src/services/formatting/rules.ts index 0b6a6ad0bdc..4686616c3cc 100644 --- a/src/services/formatting/rules.ts +++ b/src/services/formatting/rules.ts @@ -231,7 +231,7 @@ module ts.formatting { this.NoSpaceBeforeOpenBracket = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.OpenBracketToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); this.NoSpaceAfterOpenBracket = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBracketToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); this.NoSpaceBeforeCloseBracket = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBracketToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); - this.NoSpaceAfterCloseBracket = new Rule(RuleDescriptor.create3(SyntaxKind.CloseBracketToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + this.NoSpaceAfterCloseBracket = new Rule(RuleDescriptor.create3(SyntaxKind.CloseBracketToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBeforeBlockInFunctionDeclarationContext), RuleAction.Delete)); // Place a space before open brace in a function declaration this.FunctionOpenBraceLeftTokenRange = Shared.TokenRange.AnyIncludingMultilineComments; @@ -650,6 +650,10 @@ module ts.formatting { return context.TokensAreOnSameLine(); } + static IsNotBeforeBlockInFunctionDeclarationContext(context: FormattingContext): boolean { + return !Rules.IsFunctionDeclContext(context) && !Rules.IsBeforeBlockContext(context) + } + static IsEndOfDecoratorContextOnSameLine(context: FormattingContext): boolean { return context.TokensAreOnSameLine() && context.contextNode.decorators && diff --git a/tests/cases/fourslash/formatOnEnterFunctionDeclaration.ts b/tests/cases/fourslash/formatOnEnterFunctionDeclaration.ts new file mode 100644 index 00000000000..bf3756059d8 --- /dev/null +++ b/tests/cases/fourslash/formatOnEnterFunctionDeclaration.ts @@ -0,0 +1,8 @@ +/// + +/////*0*/function listAPIFiles(path: string): string[] {/*1*/ } + +goTo.marker("1"); +edit.insertLine(""); +goTo.marker("0"); +verify.currentLineContentIs("function listAPIFiles(path: string): string[] {"); \ No newline at end of file