From 94e6a817df843960d90c8b43e5248bc31d0e0c76 Mon Sep 17 00:00:00 2001 From: Alan Pierce Date: Sun, 24 Jun 2018 21:36:34 -0700 Subject: [PATCH] Fix crash on class fields that don't end in a semicolon (#271) Fixes #235 The previous code always ate the next token after a class field, which was a semicolon in all test cases so far. However, if the class field didn't end in a semicolon, it would eat the first token of the next class body member, which would confuse all downstream code and lead to errors. This means we end up leaving semicolons around in class bodies where class fields were, but this shouldn't cause problems, and it seems best to keep the transforms simple. --- src/util/getClassInfo.ts | 1 - test/flow-test.ts | 4 +-- test/sucrase-test.ts | 56 ++++++++++++++++++++++++++++++++++++---- test/types-test.ts | 6 ++--- test/typescript-test.ts | 28 ++++++++++---------- 5 files changed, 70 insertions(+), 25 deletions(-) diff --git a/src/util/getClassInfo.ts b/src/util/getClassInfo.ts index ca3606b8..1b756cfd 100644 --- a/src/util/getClassInfo.ts +++ b/src/util/getClassInfo.ts @@ -104,7 +104,6 @@ export default function getClassInfo( classInitializers.push(`this${nameCode} =${expressionCode}`); } } - tokens.nextToken(); fieldRanges.push({start: statementStartIndex, end: tokens.currentIndex()}); } } diff --git a/test/flow-test.ts b/test/flow-test.ts index 2280ea33..92de0a66 100644 --- a/test/flow-test.ts +++ b/test/flow-test.ts @@ -54,8 +54,8 @@ describe("transform flow", () => { `, `"use strict"; class C { - - + ; + ; } `, ); diff --git a/test/sucrase-test.ts b/test/sucrase-test.ts index 107add1b..4324aec6 100644 --- a/test/sucrase-test.ts +++ b/test/sucrase-test.ts @@ -284,7 +284,7 @@ describe("sucrase", () => { `, `"use strict"; class A { - + ; } A.x = 3; `, {transforms: ["jsx", "imports", "typescript"]}, @@ -300,7 +300,7 @@ describe("sucrase", () => { `, `"use strict"; var _class; const A = (_class = class { - + ; }, _class.x = 3, _class) `, {transforms: ["jsx", "imports", "typescript"]}, @@ -316,7 +316,7 @@ describe("sucrase", () => { `, `"use strict";${ESMODULE_PREFIX} class C { - + ; } C.x = 3; exports.default = C; `, {transforms: ["jsx", "imports", "typescript"]}, @@ -337,8 +337,8 @@ describe("sucrase", () => { var _A = require('A'); var _A2 = _interopRequireDefault(_A); var _B = require('B'); var _B2 = _interopRequireDefault(_B); class C {constructor() { this.a = _A2.default; } - - + ; + ; } C.b = _B2.default; `, {transforms: ["jsx", "imports", "typescript"]}, @@ -505,4 +505,50 @@ describe("sucrase", () => { {transforms: ["jsx", "imports", "typescript"]}, ); }); + + it("handles a static class field without a semicolon", () => { + assertResult( + ` + class A { + static b = {} + c () { + const d = 1; + } + } + `, + `"use strict"; + class A { + + c () { + const d = 1; + } + } A.b = {}; + `, + {transforms: ["imports"]}, + ); + }); + + it("handles a class with class field bound methods", () => { + assertResult( + ` + export class Observer { + update = (v: any) => {} + complete = () => {} + error = (err: any) => {} + } + + export default function() {} + `, + `"use strict";${ESMODULE_PREFIX} + class Observer {constructor() { this.update = (v) => {};this.complete = () => {};this.error = (err) => {}; } + + + + } exports.Observer = Observer; + + exports. default = function() {} + `, + {transforms: ["imports", "typescript"]}, + ); + }); }); diff --git a/test/types-test.ts b/test/types-test.ts index 673d4414..b120e800 100644 --- a/test/types-test.ts +++ b/test/types-test.ts @@ -119,8 +119,8 @@ describe("type transforms", () => { `, `"use strict"; class A {constructor() { this.x = 2;this.y = {}; } - - + ; + ; } `, ); @@ -135,7 +135,7 @@ describe("type transforms", () => { `, `"use strict"; class A { - + ; } `, ); diff --git a/test/typescript-test.ts b/test/typescript-test.ts index 84d82617..f1deab42 100644 --- a/test/typescript-test.ts +++ b/test/typescript-test.ts @@ -53,7 +53,7 @@ describe("typescript transform", () => { `, `"use strict"; class A { - + ; c() { return "hi"; } @@ -74,7 +74,7 @@ describe("typescript transform", () => { `, `"use strict"; class A { - + ; constructor() {;this.x = 1; this.y = 2; } @@ -95,7 +95,7 @@ describe("typescript transform", () => { `, `"use strict"; class A extends B { - + ; constructor(a) { super(a);this.x = 1;; } @@ -113,7 +113,7 @@ describe("typescript transform", () => { `, `"use strict"; class A {constructor() { this.x = 1; } - + ; } `, ); @@ -128,7 +128,7 @@ describe("typescript transform", () => { `, `"use strict"; class A extends B {constructor(...args) { super(...args); this.x = 1; } - + ; } `, ); @@ -143,7 +143,7 @@ describe("typescript transform", () => { `, `"use strict"; class A extends B {constructor(...args2) { super(...args2); this.args = 1; } - + ; } `, ); @@ -307,8 +307,8 @@ describe("typescript transform", () => { `, `"use strict"; class A {constructor() { this.f = function() {}; } - - + ; + ; } `, ); @@ -362,9 +362,9 @@ describe("typescript transform", () => { `, `"use strict"; class A {constructor() { this[a + b] = 3;this[0] = 1;this["Hello, world"] = 2; } - - - + ; + ; + ; } `, ); @@ -698,7 +698,7 @@ describe("typescript transform", () => { `, `"use strict"; class A { - + ; constructor() {;this.x = 1; } } @@ -834,7 +834,7 @@ describe("typescript transform", () => { `, `"use strict"; class A { - + ; getFoo() { return foo; } @@ -968,7 +968,7 @@ describe("typescript transform", () => { `, `"use strict"; class A {constructor() { this.n = 3; } - + ; } `, );