Skip to content

Commit

Permalink
Add support for parsing declare TS class fields (#537)
Browse files Browse the repository at this point in the history
Fixes #536

We already completely remove uninitialized class fields for now, which agrees
with the `declare` behavior, so the only change needed here was to parse the
syntax without crashing. In the future, when we remove the class fields
transform, we'll need to distinguish declare vs non-declare fields.
  • Loading branch information
alangpierce authored May 18, 2020
1 parent 9b20ea5 commit a4a596e
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 10 deletions.
26 changes: 16 additions & 10 deletions src/parser/plugins/typescript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ export function tsParseModifier(
case ContextualKeyword._protected:
state.tokens[state.tokens.length - 1].type = tt._protected;
break;
case ContextualKeyword._declare:
state.tokens[state.tokens.length - 1].type = tt._declare;
break;
default:
break;
}
Expand Down Expand Up @@ -1213,18 +1216,21 @@ export function tsTryParseClassMemberWithIsStatic(
let isAbstract = false;
let isReadonly = false;

const mod = tsParseModifier([ContextualKeyword._abstract, ContextualKeyword._readonly]);
switch (mod) {
case ContextualKeyword._readonly:
isReadonly = true;
isAbstract = !!tsParseModifier([ContextualKeyword._abstract]);
while (true) {
const mod = tsParseModifier([
ContextualKeyword._abstract,
ContextualKeyword._readonly,
ContextualKeyword._declare,
]);
if (mod == null) {
break;
case ContextualKeyword._abstract:
}
if (mod === ContextualKeyword._readonly) {
isReadonly = true;
}
if (mod === ContextualKeyword._abstract) {
isAbstract = true;
isReadonly = !!tsParseModifier([ContextualKeyword._readonly]);
break;
default:
break;
}
}

// We no longer check for public/private/etc, but tsTryParseIndexSignature should just return
Expand Down
2 changes: 2 additions & 0 deletions src/parser/traverser/statement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -688,7 +688,9 @@ function parseClassBody(classContextId: number): void {

function parseClassMember(memberStart: number, classContextId: number): void {
if (isTypeScriptEnabled) {
eatContextual(ContextualKeyword._declare);
tsParseAccessModifier();
eatContextual(ContextualKeyword._declare);
}
let isStatic = false;
if (match(tt.name) && state.contextualKeyword === ContextualKeyword._static) {
Expand Down
1 change: 1 addition & 0 deletions src/util/getClassInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ function isAccessModifier(token: Token): boolean {
tt._protected,
tt._abstract,
tt.star,
tt._declare,
].includes(token.type);
}

Expand Down
37 changes: 37 additions & 0 deletions test/typescript-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2107,4 +2107,41 @@ describe("typescript transform", () => {
`,
);
});

it("properly removes class fields with declare", () => {
assertTypeScriptResult(
`
class Foo {
declare a: number;
public declare b: number;
declare public c: number;
static declare d: number;
declare static e: number;
declare public static f: number;
public declare static g: number;
public static declare h: number;
constructor() {
console.log('Hi');
}
}
`,
`"use strict";
class Foo {
constructor() {
console.log('Hi');
}
}
`,
);
});
});
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"downlevelIteration": true,
"noEmitHelpers": true,
"importHelpers": true,
"useDefineForClassFields": true,
"plugins": [
{
"name": "typescript-tslint-plugin",
Expand Down

0 comments on commit a4a596e

Please sign in to comment.