Skip to content

Commit

Permalink
Allow super.method() calls in constructor
Browse files Browse the repository at this point in the history
The old code assumed that `super` always followed by a `(` which is not
the case.

Also adds tests for invalid (at runtime) code with multiple `super()`
and `super.m()` / `super.x` / `super.x = 1` before `super()`.

Fixes alangpierce#323
  • Loading branch information
arv committed Oct 26, 2018
1 parent 2cbe6fc commit 6e132a7
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 8 deletions.
20 changes: 12 additions & 8 deletions src/util/getClassInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,17 +209,21 @@ function processConstructor(
let constructorInsertPos = tokens.currentIndex();

// Advance through body looking for a super call.
let foundSuperCall = false;
while (!tokens.matchesContextIdAndLabel(tt.braceR, constructorContextId)) {
if (tokens.matches1(tt._super)) {
if (!foundSuperCall && tokens.matches1(tt._super)) {
tokens.nextToken();
const superCallContextId = tokens.currentToken().contextId;
if (superCallContextId == null) {
throw new Error("Expected a context ID on the super call");
}
while (!tokens.matchesContextIdAndLabel(tt.parenR, superCallContextId)) {
tokens.nextToken();
if (tokens.matches1(tt.parenL)) {
const superCallContextId = tokens.currentToken().contextId;
if (superCallContextId == null) {
throw new Error("Expected a context ID on the super call");
}
while (!tokens.matchesContextIdAndLabel(tt.parenR, superCallContextId)) {
tokens.nextToken();
}
constructorInsertPos = tokens.currentIndex();
foundSuperCall = true;
}
constructorInsertPos = tokens.currentIndex();
}
tokens.nextToken();
}
Expand Down
119 changes: 119 additions & 0 deletions test/typescript-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,125 @@ describe("typescript transform", () => {
);
});

it("handles class field assignment after a constructor with multiple super calls", () => {
assertTypeScriptResult(
`
class A extends B {
x = 1;
constructor(a) {
super(a);
super(b);
}
}
`,
`"use strict";const __init = Symbol();
class A extends B {
[__init]() {this.x = 1}
constructor(a) {
super(a);this[__init]();;
super(b);
}
}
`,
);
});

it("handles class field assignment after a constructor with super and super method call", () => {
assertTypeScriptResult(
`
class A extends B {
x = 1;
constructor(a) {
super(a);
super.b();
}
}
`,
`"use strict";const __init = Symbol();
class A extends B {
[__init]() {this.x = 1}
constructor(a) {
super(a);this[__init]();;
super.b();
}
}
`,
);
});

it("handles class field assignment after a constructor with invalid super method before super call", () => {
assertTypeScriptResult(
`
class A extends B {
x = 1;
constructor(a) {
super.b();
super(a);
}
}
`,
`"use strict";const __init = Symbol();
class A extends B {
[__init]() {this.x = 1}
constructor(a) {
super.b();
super(a);this[__init]();;
}
}
`,
);
});

it("handles class field assignment after a constructor with super prop", () => {
assertTypeScriptResult(
`
class A extends B {
x = 1;
constructor(a) {
super();
super.a;
super.b = 1;
}
}
`,
`"use strict";const __init = Symbol();
class A extends B {
[__init]() {this.x = 1}
constructor(a) {
super();this[__init]();;
super.a;
super.b = 1;
}
}
`,
);
});

it("handles class field assignment after a constructor with invalid super prop before super call", () => {
assertTypeScriptResult(
`
class A extends B {
x = 1;
constructor(a) {
super.a;
super.b = 1;
super();
}
}
`,
`"use strict";const __init = Symbol();
class A extends B {
[__init]() {this.x = 1}
constructor(a) {
super.a;
super.b = 1;
super();this[__init]();;
}
}
`,
);
});

it("handles class field assignment with no constructor", () => {
assertTypeScriptResult(
`
Expand Down

0 comments on commit 6e132a7

Please # to comment.