diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index b1dcbfbcd95..a0c887414cd 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -3036,9 +3036,30 @@ module ts { if (tryEmitConstantValue(node)) { return; } + emit(node.expression); + + var indented = false; + var isSynthesied = nodeIsSynthesized(node); + if (!isSynthesied && !nodeEndIsOnSameLineAsNodeStart(node.expression, node.dotToken)) { + indented = true; + increaseIndent(); + writeLine(); + } + write("."); + + if (!isSynthesied && !nodeEndIsOnSameLineAsNodeStart(node.dotToken, node.name) && !indented) { + indented = true; + increaseIndent(); + writeLine(); + } + emit(node.name); + + if (indented) { + decreaseIndent(); + } } function emitQualifiedName(node: QualifiedName) { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 0bb09330070..557d6505984 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -120,6 +120,7 @@ module ts { return visitNodes(cbNodes, (node).properties); case SyntaxKind.PropertyAccessExpression: return visitNode(cbNode, (node).expression) || + visitNode(cbNode, (node).dotToken) || visitNode(cbNode, (node).name); case SyntaxKind.ElementAccessExpression: return visitNode(cbNode, (node).expression) || @@ -1326,13 +1327,16 @@ module ts { function parseOptionalToken(t: SyntaxKind): Node { if (token === t) { - var node = createNode(t); - nextToken(); - return finishNode(node); + return parseTokenNode(); } return undefined; } + function parseExpectedToken(t: SyntaxKind, reportAtCurrentPosition: boolean, diagnosticMessage: DiagnosticMessage, arg0?: any): Node { + return parseOptionalToken(t) || + createMissingNode(t, reportAtCurrentPosition, diagnosticMessage, arg0); + } + function parseTokenNode(): T { var node = createNode(token); nextToken(); @@ -2150,8 +2154,7 @@ module ts { literal = parseLiteralNode(); } else { - literal = createMissingNode( - SyntaxKind.TemplateTail, /*reportAtCurrentPosition:*/ false, Diagnostics._0_expected, tokenToString(SyntaxKind.CloseBraceToken)); + literal = parseExpectedToken(SyntaxKind.TemplateTail, /*reportAtCurrentPosition:*/ false, Diagnostics._0_expected, tokenToString(SyntaxKind.CloseBraceToken)); } span.literal = literal; @@ -3446,7 +3449,7 @@ module ts { // If it wasn't then just try to parse out a '.' and report an error. var node = createNode(SyntaxKind.PropertyAccessExpression, expression.pos); node.expression = expression; - parseExpected(SyntaxKind.DotToken, Diagnostics.super_must_be_followed_by_an_argument_list_or_member_access); + node.dotToken = parseExpectedToken(SyntaxKind.DotToken, /*reportAtCurrentPosition:*/ false, Diagnostics.super_must_be_followed_by_an_argument_list_or_member_access); node.name = parseRightSideOfDot(/*allowIdentifierNames:*/ true); return finishNode(node); } @@ -3462,10 +3465,11 @@ module ts { function parseMemberExpressionRest(expression: LeftHandSideExpression): MemberExpression { while (true) { - var dotOrBracketStart = scanner.getTokenPos(); - if (parseOptional(SyntaxKind.DotToken)) { + var dotToken = parseOptionalToken(SyntaxKind.DotToken); + if (dotToken) { var propertyAccess = createNode(SyntaxKind.PropertyAccessExpression, expression.pos); propertyAccess.expression = expression; + propertyAccess.dotToken = dotToken; propertyAccess.name = parseRightSideOfDot(/*allowIdentifierNames:*/ true); expression = finishNode(propertyAccess); continue; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index c7339bcd60d..97706ac324b 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -693,6 +693,7 @@ module ts { export interface PropertyAccessExpression extends MemberExpression { expression: LeftHandSideExpression; + dotToken: Node; name: Identifier; } diff --git a/tests/baselines/reference/APISample_compile.js b/tests/baselines/reference/APISample_compile.js index 30fe1d09060..f10e9c9030c 100644 --- a/tests/baselines/reference/APISample_compile.js +++ b/tests/baselines/reference/APISample_compile.js @@ -579,6 +579,7 @@ declare module "typescript" { } interface PropertyAccessExpression extends MemberExpression { expression: LeftHandSideExpression; + dotToken: Node; name: Identifier; } interface ElementAccessExpression extends MemberExpression { diff --git a/tests/baselines/reference/APISample_compile.types b/tests/baselines/reference/APISample_compile.types index 81b98949c7b..1365a0e903b 100644 --- a/tests/baselines/reference/APISample_compile.types +++ b/tests/baselines/reference/APISample_compile.types @@ -1743,6 +1743,10 @@ declare module "typescript" { >expression : LeftHandSideExpression >LeftHandSideExpression : LeftHandSideExpression + dotToken: Node; +>dotToken : Node +>Node : Node + name: Identifier; >name : Identifier >Identifier : Identifier diff --git a/tests/baselines/reference/APISample_linter.js b/tests/baselines/reference/APISample_linter.js index b7a67081440..3e8c579a051 100644 --- a/tests/baselines/reference/APISample_linter.js +++ b/tests/baselines/reference/APISample_linter.js @@ -610,6 +610,7 @@ declare module "typescript" { } interface PropertyAccessExpression extends MemberExpression { expression: LeftHandSideExpression; + dotToken: Node; name: Identifier; } interface ElementAccessExpression extends MemberExpression { diff --git a/tests/baselines/reference/APISample_linter.types b/tests/baselines/reference/APISample_linter.types index 6da030e8617..0f428ecdec2 100644 --- a/tests/baselines/reference/APISample_linter.types +++ b/tests/baselines/reference/APISample_linter.types @@ -1889,6 +1889,10 @@ declare module "typescript" { >expression : LeftHandSideExpression >LeftHandSideExpression : LeftHandSideExpression + dotToken: Node; +>dotToken : Node +>Node : Node + name: Identifier; >name : Identifier >Identifier : Identifier diff --git a/tests/baselines/reference/APISample_transform.js b/tests/baselines/reference/APISample_transform.js index c30d4f03456..4cd5c5c0983 100644 --- a/tests/baselines/reference/APISample_transform.js +++ b/tests/baselines/reference/APISample_transform.js @@ -611,6 +611,7 @@ declare module "typescript" { } interface PropertyAccessExpression extends MemberExpression { expression: LeftHandSideExpression; + dotToken: Node; name: Identifier; } interface ElementAccessExpression extends MemberExpression { diff --git a/tests/baselines/reference/APISample_transform.types b/tests/baselines/reference/APISample_transform.types index 42862def15f..b78b0565a45 100644 --- a/tests/baselines/reference/APISample_transform.types +++ b/tests/baselines/reference/APISample_transform.types @@ -1839,6 +1839,10 @@ declare module "typescript" { >expression : LeftHandSideExpression >LeftHandSideExpression : LeftHandSideExpression + dotToken: Node; +>dotToken : Node +>Node : Node + name: Identifier; >name : Identifier >Identifier : Identifier diff --git a/tests/baselines/reference/APISample_watcher.js b/tests/baselines/reference/APISample_watcher.js index a9ed17e924d..139af5b7cd2 100644 --- a/tests/baselines/reference/APISample_watcher.js +++ b/tests/baselines/reference/APISample_watcher.js @@ -648,6 +648,7 @@ declare module "typescript" { } interface PropertyAccessExpression extends MemberExpression { expression: LeftHandSideExpression; + dotToken: Node; name: Identifier; } interface ElementAccessExpression extends MemberExpression { @@ -2108,7 +2109,9 @@ function watch(rootFileNames, options) { }); } function logErrors(fileName) { - var allDiagnostics = services.getCompilerOptionsDiagnostics().concat(services.getSyntacticDiagnostics(fileName)).concat(services.getSemanticDiagnostics(fileName)); + var allDiagnostics = services.getCompilerOptionsDiagnostics() + .concat(services.getSyntacticDiagnostics(fileName)) + .concat(services.getSemanticDiagnostics(fileName)); allDiagnostics.forEach(function (diagnostic) { if (diagnostic.file) { var lineChar = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start); @@ -2121,6 +2124,7 @@ function watch(rootFileNames, options) { } } // Initialize files constituting the program as all .ts files in the current directory -var currentDirectoryFiles = fs.readdirSync(process.cwd()).filter(function (fileName) { return fileName.length >= 3 && fileName.substr(fileName.length - 3, 3) === ".ts"; }); +var currentDirectoryFiles = fs.readdirSync(process.cwd()). + filter(function (fileName) { return fileName.length >= 3 && fileName.substr(fileName.length - 3, 3) === ".ts"; }); // Start the watcher watch(currentDirectoryFiles, { module: 1 /* CommonJS */ }); diff --git a/tests/baselines/reference/APISample_watcher.types b/tests/baselines/reference/APISample_watcher.types index 3dd324c421e..5570c9ff12a 100644 --- a/tests/baselines/reference/APISample_watcher.types +++ b/tests/baselines/reference/APISample_watcher.types @@ -2012,6 +2012,10 @@ declare module "typescript" { >expression : LeftHandSideExpression >LeftHandSideExpression : LeftHandSideExpression + dotToken: Node; +>dotToken : Node +>Node : Node + name: Identifier; >name : Identifier >Identifier : Identifier diff --git a/tests/baselines/reference/arrayConcatMap.js b/tests/baselines/reference/arrayConcatMap.js index dc7272b7223..715ca158a43 100644 --- a/tests/baselines/reference/arrayConcatMap.js +++ b/tests/baselines/reference/arrayConcatMap.js @@ -3,4 +3,5 @@ var x = [].concat([{ a: 1 }], [{ a: 2 }]) .map(b => b.a); //// [arrayConcatMap.js] -var x = [].concat([{ a: 1 }], [{ a: 2 }]).map(function (b) { return b.a; }); +var x = [].concat([{ a: 1 }], [{ a: 2 }]) + .map(function (b) { return b.a; }); diff --git a/tests/baselines/reference/enumConflictsWithGlobalIdentifier.js b/tests/baselines/reference/enumConflictsWithGlobalIdentifier.js index 67d9a020bb6..a0a6afb172f 100644 --- a/tests/baselines/reference/enumConflictsWithGlobalIdentifier.js +++ b/tests/baselines/reference/enumConflictsWithGlobalIdentifier.js @@ -11,5 +11,6 @@ var Position; (function (Position) { Position[Position["IgnoreRulesSpecific"] = 0] = "IgnoreRulesSpecific"; })(Position || (Position = {})); -var x = IgnoreRulesSpecific.; +var x = IgnoreRulesSpecific. +; var y = 0 /* IgnoreRulesSpecific */; diff --git a/tests/baselines/reference/enumMemberResolution.js b/tests/baselines/reference/enumMemberResolution.js index e1d79ebeb92..ebfcac3a59e 100644 --- a/tests/baselines/reference/enumMemberResolution.js +++ b/tests/baselines/reference/enumMemberResolution.js @@ -12,6 +12,7 @@ var Position2; (function (Position2) { Position2[Position2["IgnoreRulesSpecific"] = 0] = "IgnoreRulesSpecific"; })(Position2 || (Position2 = {})); -var x = IgnoreRulesSpecific.; // error +var x = IgnoreRulesSpecific. +; // error var y = 1; var z = 0 /* IgnoreRulesSpecific */; // no error diff --git a/tests/baselines/reference/functionsMissingReturnStatementsAndExpressions.js b/tests/baselines/reference/functionsMissingReturnStatementsAndExpressions.js index ae8e7d9c918..592a03d7158 100644 --- a/tests/baselines/reference/functionsMissingReturnStatementsAndExpressions.js +++ b/tests/baselines/reference/functionsMissingReturnStatementsAndExpressions.js @@ -228,7 +228,8 @@ var C = (function () { // Not fine, since we can *only* consist of a single throw statement // if no return statements are present but we are a get accessor. throw null; - throw undefined.; + throw undefined. + ; }, enumerable: true, configurable: true diff --git a/tests/baselines/reference/genericChainedCalls.js b/tests/baselines/reference/genericChainedCalls.js index 71d83a906bf..a738e19023b 100644 --- a/tests/baselines/reference/genericChainedCalls.js +++ b/tests/baselines/reference/genericChainedCalls.js @@ -15,8 +15,9 @@ var s3 = s2.func(num => num.toString()) //// [genericChainedCalls.js] -var r1 = v1.func(function (num) { return num.toString(); }).func(function (str) { return str.length; }) // error, number doesn't have a length -.func(function (num) { return num.toString(); }); +var r1 = v1.func(function (num) { return num.toString(); }) + .func(function (str) { return str.length; }) // error, number doesn't have a length + .func(function (num) { return num.toString(); }); var s1 = v1.func(function (num) { return num.toString(); }); var s2 = s1.func(function (str) { return str.length; }); // should also error var s3 = s2.func(function (num) { return num.toString(); }); diff --git a/tests/baselines/reference/overEagerReturnTypeSpecialization.js b/tests/baselines/reference/overEagerReturnTypeSpecialization.js index 67d2005eca9..90fcc388b76 100644 --- a/tests/baselines/reference/overEagerReturnTypeSpecialization.js +++ b/tests/baselines/reference/overEagerReturnTypeSpecialization.js @@ -17,6 +17,6 @@ var r2: I1 = v1.func(num => num.toString()) // Correctly returns an I1 -.func(function (str) { return str.length; }); // should error + .func(function (str) { return str.length; }); // should error var r2 = v1.func(function (num) { return num.toString(); }) // Correctly returns an I1 -.func(function (str) { return str.length; }); // should be ok + .func(function (str) { return str.length; }); // should be ok diff --git a/tests/baselines/reference/parse1.js b/tests/baselines/reference/parse1.js index 08af81bda17..4804e31adcd 100644 --- a/tests/baselines/reference/parse1.js +++ b/tests/baselines/reference/parse1.js @@ -8,5 +8,6 @@ function foo() { //// [parse1.js] var bar = 42; function foo() { - bar.; + bar. + ; } diff --git a/tests/baselines/reference/parser509667.js b/tests/baselines/reference/parser509667.js index 21e0bc55ce4..0938613b295 100644 --- a/tests/baselines/reference/parser509667.js +++ b/tests/baselines/reference/parser509667.js @@ -16,7 +16,8 @@ var Foo = (function () { function Foo() { } Foo.prototype.f1 = function () { - if (this.) + if (this. + ) ; }; Foo.prototype.f2 = function () { diff --git a/tests/baselines/reference/underscoreTest1.js b/tests/baselines/reference/underscoreTest1.js index a4fa2cbc65d..ddd5201b858 100644 --- a/tests/baselines/reference/underscoreTest1.js +++ b/tests/baselines/reference/underscoreTest1.js @@ -1018,7 +1018,11 @@ _.omit({ name: 'moe', age: 50, userid: 'moe1' }, 'userid'); var iceCream = { flavor: "chocolate" }; _.defaults(iceCream, { flavor: "vanilla", sprinkles: "lots" }); _.clone({ name: 'moe' }); -_.chain([1, 2, 3, 200]).filter(function (num) { return num % 2 == 0; }).tap(alert).map(function (num) { return num * num; }).value(); +_.chain([1, 2, 3, 200]) + .filter(function (num) { return num % 2 == 0; }) + .tap(alert) + .map(function (num) { return num * num; }) + .value(); _.has({ a: 1, b: 2, c: 3 }, "b"); var moe = { name: 'moe', luckyNumbers: [13, 27, 34] }; var clone = { name: 'moe', luckyNumbers: [13, 27, 34] }; diff --git a/tests/baselines/reference/wrappedIncovations1.js b/tests/baselines/reference/wrappedIncovations1.js new file mode 100644 index 00000000000..b9e5ed688f9 --- /dev/null +++ b/tests/baselines/reference/wrappedIncovations1.js @@ -0,0 +1,11 @@ +//// [wrappedIncovations1.ts] +var v = this + .foo() + .bar() + .baz(); + +//// [wrappedIncovations1.js] +var v = this + .foo() + .bar() + .baz(); diff --git a/tests/baselines/reference/wrappedIncovations1.types b/tests/baselines/reference/wrappedIncovations1.types new file mode 100644 index 00000000000..32f7bb0e1b8 --- /dev/null +++ b/tests/baselines/reference/wrappedIncovations1.types @@ -0,0 +1,20 @@ +=== tests/cases/compiler/wrappedIncovations1.ts === +var v = this +>v : any +>this .foo() .bar() .baz() : any +>this .foo() .bar() .baz : any +>this .foo() .bar() : any +>this .foo() .bar : any +>this .foo() : any +>this .foo : any +>this : any + + .foo() +>foo : any + + .bar() +>bar : any + + .baz(); +>baz : any + diff --git a/tests/baselines/reference/wrappedIncovations2.js b/tests/baselines/reference/wrappedIncovations2.js new file mode 100644 index 00000000000..09951996c94 --- /dev/null +++ b/tests/baselines/reference/wrappedIncovations2.js @@ -0,0 +1,11 @@ +//// [wrappedIncovations2.ts] +var v = this. + foo(). + bar(). + baz(); + +//// [wrappedIncovations2.js] +var v = this. + foo(). + bar(). + baz(); diff --git a/tests/baselines/reference/wrappedIncovations2.types b/tests/baselines/reference/wrappedIncovations2.types new file mode 100644 index 00000000000..96337796bcd --- /dev/null +++ b/tests/baselines/reference/wrappedIncovations2.types @@ -0,0 +1,20 @@ +=== tests/cases/compiler/wrappedIncovations2.ts === +var v = this. +>v : any +>this. foo(). bar(). baz() : any +>this. foo(). bar(). baz : any +>this. foo(). bar() : any +>this. foo(). bar : any +>this. foo() : any +>this. foo : any +>this : any + + foo(). +>foo : any + + bar(). +>bar : any + + baz(); +>baz : any + diff --git a/tests/cases/compiler/wrappedIncovations1.ts b/tests/cases/compiler/wrappedIncovations1.ts new file mode 100644 index 00000000000..2c8ee00fe0e --- /dev/null +++ b/tests/cases/compiler/wrappedIncovations1.ts @@ -0,0 +1,4 @@ +var v = this + .foo() + .bar() + .baz(); \ No newline at end of file diff --git a/tests/cases/compiler/wrappedIncovations2.ts b/tests/cases/compiler/wrappedIncovations2.ts new file mode 100644 index 00000000000..eba99b425e4 --- /dev/null +++ b/tests/cases/compiler/wrappedIncovations2.ts @@ -0,0 +1,4 @@ +var v = this. + foo(). + bar(). + baz(); \ No newline at end of file diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index 54adcaf345f..e785f1cdf00 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -664,7 +664,7 @@ module m3 { }\ var oldText = ScriptSnapshot.fromString(source); var newTextAndChange = withInsert(oldText, 0, ""); - compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 7); + compareTrees(oldText, newTextAndChange.text, newTextAndChange.textChangeRange, 8); }); it('Class to interface',() => {