Skip to content

Commit

Permalink
Port babel-parser changes from 2020-07-22 to 2020-11-25 (#567)
Browse files Browse the repository at this point in the history
Fixes #561

01d4625412 Correctly check reserved word for PropertyDefinition: IdentifierReference (#11862)
🚫 Only affects reserved word checking, which Sucrase doesn't do.

45fdb87747 v7.11.0
🚫 Release only.

a4ebe29b3f Parser refactoring (#11871)
🚫 None of the refactors stood out as being important to port.

a1eabb84ea rescan gt/lt token after TsAsExpression is parsed (#11912)
✅ I fixed the `>=` bug in a different way by rearranging `readToken_lt_gt`. I
also discovered a similar bug with `<`, which I filed as #562.

953ae82159 v7.11.1
🚫 Release only.

92434269af fix: do not eat get/set after async is parsed (#11916)
🚫 Fix for regression never applied to Sucrase.

bc7a811fce v7.11.2
🚫 Release only.

50b3262063 refactor: avoid unnecessary property access (#11918)
🚫 Not relevant to Sucrase.

c0f6f0394d Support ConditionalExpressions in dry-error-messages rule (#11917)
🚫 Only error reporting.

cd577eedfd refactor: add recoverable error on accessorIsGenerator (#11921)
🚫 Only related to error reporting.

76f033f8c7 simplify isLookaheadRelational method (#11922)
🚫 Method doesn't exist in Sucrase anymore.

a827ca41f3 refactor: simplify smart pipeline parsing (#11919)
🚫 Pipeline code currently not in Sucrase.

57b658c4d8 v7.11.3
🚫 Release only.

4bb1e164da Refactor [In] production parameter tracking (#11930)
🚫 I'll leave alone for now. It's not clear that moving to a global production
stack is the best approach for Sucrase.

a3893129ec chore: enable flowcheck on CI (#11945)
🚫 Just changes to parser types.

008fe25ae2 fix: reset EndLocation for catch param (#11943)
🚫 Only affects AST.

3995160fc7 fix: push new token context when braceHashL is seen (#11941)
🚫 Sucrase doesn't use token contexts.

df9ee2c7cd Simplify tokenizer update context (#11944)
🚫 Sucrase doesn't use token contexts.

66c6b3b949 Add more parser test cases (#11923)
🚫 The test cases don't seem particularly useful for Sucrase, so I won't port
them.

cdada5800d fix: do not transform ClassPrivateMethods in estree (#11973)
🚫 Test only, and Sucrase doesn't have estree support.

96cc8292b7 Fix parsing type casted generic flow arrow exprs (#11955)
🚫 Appears to already be working fine in Sucrase.

84ea6e4501 Throw error on invalid flow async generic arrow syntax (#11979)
🚫 Validation only.

90b1989569 v7.11.4
🚫 Release only.

941f610275 Set generator to true during error recovery of accessor (#11987)
🚫 AST only.

3fad7eab9b Use Yarn 2 (#11962)
🚫 Tooling only.

2c60595342 fix: ExpressionBody should respect [In] parameter (#11931)
🚫 Fix for infinite loop that doesn't appear to happen in Sucrase.

af64ccb2b0 v7.11.5
🚫 Release only.

bbe0cf09fc Throw a syntax error for a parameter properties in not constructor (#12061)
🚫 Error handling only.

7028a14c7f fix: throw for constructors with type parameters (#12065)
🚫 Error handling only.

ae18f9c0d9 Throw a syntax error for a declare function with a body (#12054)
🚫 Error handling only.

18d13d0032 Fix invalid `setter` parse (#12076)
🚫 Only affects estree.

3628c52867 Do not throw an error for optional binding pattern params in function declaration (#12085)
🚫 Error handling only.

cb4e436018 Throw an error for a declare class field that have an initializer (#12093)
🚫 Error handling only.

a4a14caee7 Throw a syntax error for empty type parameter/argument (#12088)
🚫 Error handling only.

0d32e3fc36 Add missing tests for TypeScript syntax errors (#12103)
🚫 Error handling only.

434b65bc2a [ts] Throw a syntax error for index signature with `declare` (#12111)
🚫 Error handling only.

39a12674b4 Improve syntax error for class fields in ambient context (#12108)
🚫 Error handling only.

45f0cc2ed9 Recover from error for missing initializer in const declaration (#12120)
🚫 Error handling only.

13a1cfd396 Move check for TSTypeCastExpression to catch another case (#12161)
🚫 Error handling only.

a5bed04f55 Make asserts property boolean, not undefined (#12167)
🚫 AST only.

21d7ee2610 String import/export specifier (#12091)
🚫 Filed as #565

136e6301cb Check if param is assignable when parsing arrow return type (#11992)
🚫 Later reverted, issue still not fixed.

9f40d6fcd0 [ts] Add support for the "intrinsic" keyword (#12147)
🚫 It should be fine to treat intrinsic as an identifier.

3fd963fdc8 [ts] Add support for template interpolations in types (#12131)
✅ Implemented in a way that's a little more explicit than Babel's
inheritance-based approach, but otherwise similar.

6830c90ac9 Support TypeScript mapped type 'as' clauses (#12129)
✅ Implemented directly.

3ccca88178 Parse class static block (#12079)
✅ Implemented in a reasonably straightforward way, and I also had to change the
class fields implementation to properly traverse static blocks.

59d97d9bca [parser] Better error message for missing number exponent (#12072)
🚫 Error handling only.

af8e0facc1 Parse import-assertions (#12139)
🚫 Filed #566 to do this in a follow-up task

91a7a64b4b Revert "Fix: check if param is assignable when parsing arrow return type annotation" (#12173)
🚫 Later reverted, issue still not fixed.

726154c78e v7.12.0
🚫 Release only.

84987a00e6 Reland "Fix: check if param is assignable when parsing arrow return type annotation" (#12183)
🚫 Later reverted, issue still not fixed.

eec01fe078 chore: use workspace:* for dev deps (#12186)
🚫 Internal-only change.

7f4b83833f v7.12.1
🚫 Release only.

4fe8c3acc5 Revert "Fix: check if param is assignable when parsing arrow return type annotation" (#12198)
🚫 Later reverted, issue still not fixed.

a534d8746e v7.12.2
🚫 Release only.

47250ffa65 [ts] Disallow invalid type annotations in ExpressionStatements (#12185)
🚫 Error handling only.

7870465b62 [ts] Add parser test: destructuring-with-annotation-newline (#12203)
✅ Added test.

2562c8d8fa v7.12.3
🚫 Release only.

f1bc314c79 Fix parsing of imports with module string name in flow plugin (#12224)
🚫 Already filed as #565.

d51aa6d761 [ts] Allow optional binding pattern parameters within types/interfaces (#12227)
✅ Case was already working in Sucrase, but I added a test.

c00bb14f79 [ts] Error on invalid type casts in JSX (#12221)
🚫 Error handling only.

f5bd9f2013 Allows the interface to be used as an Identifier for flow plugin (#12254)
🚫 Only affects code that already has a syntax error.

faaebfe91f Support Import Assertions for re-export statement (#12249)
🚫 Added this case to the description of #566.

2782a549e9 Refactor yield await classification (#12230)
🚫 yield/await positions aren't tracked in Sucrase. We may want to better handle
ambiguous patterns via something like `ExpressionScope`, but I'll leave that off
for now.

5b48f40a08 Polish parser errors (#12258)
🚫 Error handling only.

ea2892fefc add declare to class properties type annotations (#12257)
🚫 Internal only.

a8c66f4680 Handle exprAllowed before ObjectLike is parsed  (#12267)
🚫 Sucrase doesn't use exprAllowed so didn't have this bug.

b7754d3c82 fix: disallow import assertionts in export without from (#12264)
🚫 Error handling only.

ff6c3792bb Make assertions optional and update AST spec (#12280)
🚫 AST only.

963537d5f5 [ts] Make ImportDeclaration always have `importKind` (#12170)
🚫 AST only.

766df9c369 fix: support string assertion key in assert entries (#12281)
🚫 General task tracked in #565

b649f8d192 Fix packages documentation README links. (#12289)
🚫 Documentation only.

a41da05ce9 v7.12.5
🚫 Release only.

ad8a4d62fd Fix syntax error for getter and setter with ts and estree plugin (#12333)
🚫 Bug wasn't present in Sucrase.

f80478c06d Prepare repository for gradual flow->ts migration (#12317)
🚫 Internal only.

d7e32d8c3d Add typings for `recordAndTuple` parser plugin (#12326)
🚫 Internal only.

5bbad8936b fix: disallow all parenthesized pattern except parsing LHS (#12327)
🚫 Error handling only.

a4e4aede14 [ts]Set `false` to default value of TsTypePredicate.asserts (#12352)
🚫 AST only.

b564368d6e refactor: reorder checkLVal parameters (#12346)
🚫 checkLVal doesn't exist in Sucrase.

94d116052f [ts] Allow modifiers as names of methods with type parameters (#12356)
✅ Switched to allowed list of following tokens and tests still pass. The bug
with `declare` is already filed as #545.

23226d93d4 v7.12.7
🚫 Release only.

89f3247e32 refactor: simplify isAwaitAllowed (#12398)
🚫 Refactor of unused code.
  • Loading branch information
alangpierce committed Dec 9, 2020
1 parent 80f84a6 commit 2c53710
Show file tree
Hide file tree
Showing 7 changed files with 267 additions and 33 deletions.
47 changes: 39 additions & 8 deletions src/parser/plugins/typescript.ts
Expand Up @@ -4,6 +4,7 @@ import {
lookaheadTypeAndKeyword,
match,
next,
nextTemplateToken,
popTypeContext,
pushTypeContext,
} from "../tokenizer/index";
Expand Down Expand Up @@ -59,6 +60,17 @@ function tsIsIdentifier(): boolean {
return match(tt.name);
}

function isLiteralPropertyName(): boolean {
return (
match(tt.name) ||
Boolean(state.type & TokenType.IS_KEYWORD) ||
match(tt.string) ||
match(tt.num) ||
match(tt.bigint) ||
match(tt.decimal)
);
}

function tsNextTokenCanFollowModifier(): boolean {
// Note: TypeScript's implementation is much more complicated because
// more things are considered modifiers there.
Expand All @@ -68,13 +80,13 @@ function tsNextTokenCanFollowModifier(): boolean {

next();
const canFollowModifier =
!hasPrecedingLineBreak() &&
!match(tt.parenL) &&
!match(tt.parenR) &&
!match(tt.colon) &&
!match(tt.eq) &&
!match(tt.question) &&
!match(tt.bang);
(match(tt.bracketL) ||
match(tt.braceL) ||
match(tt.star) ||
match(tt.ellipsis) ||
match(tt.hash) ||
isLiteralPropertyName()) &&
!hasPrecedingLineBreak();

if (canFollowModifier) {
return true;
Expand Down Expand Up @@ -352,6 +364,9 @@ function tsParseMappedType(): void {
}
expect(tt.bracketL);
tsParseMappedTypeParameter();
if (eatContextual(ContextualKeyword._as)) {
tsParseType();
}
expect(tt.bracketR);
if (match(tt.plus) || match(tt.minus)) {
next();
Expand Down Expand Up @@ -396,6 +411,22 @@ function tsParseParenthesizedType(): void {
expect(tt.parenR);
}

function tsParseTemplateLiteralType(): void {
// Finish `, read quasi
nextTemplateToken();
// Finish quasi, read ${
nextTemplateToken();
while (!match(tt.backQuote) && !state.error) {
expect(tt.dollarBraceL);
tsParseType();
// Finish }, read quasi
nextTemplateToken();
// Finish quasi, read either ${ or `
nextTemplateToken();
}
next();
}

enum FunctionType {
TSFunctionType,
TSConstructorType,
Expand Down Expand Up @@ -456,7 +487,7 @@ function tsParseNonArrayType(): void {
tsParseParenthesizedType();
return;
case tt.backQuote:
parseTemplate();
tsParseTemplateLiteralType();
return;
default:
if (state.type & TokenType.IS_KEYWORD) {
Expand Down
10 changes: 5 additions & 5 deletions src/parser/tokenizer/index.ts
Expand Up @@ -476,11 +476,6 @@ function readToken_plus_min(code: number): void {

// '<>'
function readToken_lt_gt(code: number): void {
// Avoid right-shift for things like Array<Array<string>>.
if (code === charCodes.greaterThan && state.isType) {
finishOp(tt.greaterThan, 1);
return;
}
const nextChar = input.charCodeAt(state.pos + 1);

if (nextChar === code) {
Expand All @@ -492,6 +487,11 @@ function readToken_lt_gt(code: number): void {
finishOp(tt.assign, size + 1);
return;
}
// Avoid right-shift for things like Array<Array<string>>.
if (code === charCodes.greaterThan && state.isType) {
finishOp(tt.greaterThan, 1);
return;
}
finishOp(tt.bitShift, size);
return;
}
Expand Down
4 changes: 2 additions & 2 deletions src/parser/traverser/expression.ts
Expand Up @@ -521,7 +521,7 @@ export function parseExprAtom(): boolean {

case tt._do: {
next();
parseBlock(false);
parseBlock();
return false;
}

Expand Down Expand Up @@ -933,7 +933,7 @@ export function parseFunctionBody(allowExpression: boolean, funcContextId: numbe
if (isExpression) {
parseMaybeAssign();
} else {
parseBlock(true /* allowDirectives */, true /* isFunctionScope */, funcContextId);
parseBlock(true /* isFunctionScope */, funcContextId);
}
}

Expand Down
19 changes: 10 additions & 9 deletions src/parser/traverser/statement.ts
Expand Up @@ -481,15 +481,8 @@ function parseIdentifierStatement(contextualKeyword: ContextualKeyword): void {
}
}

// Parse a semicolon-enclosed block of statements, handling `"use
// strict"` declarations when `allowStrict` is true (used for
// function bodies).

export function parseBlock(
allowDirectives: boolean = false,
isFunctionScope: boolean = false,
contextId: number = 0,
): void {
// Parse a semicolon-enclosed block of statements.
export function parseBlock(isFunctionScope: boolean = false, contextId: number = 0): void {
const startTokenIndex = state.tokens.length;
state.scopeDepth++;
expect(tt.braceL);
Expand Down Expand Up @@ -716,6 +709,14 @@ function parseClassMember(memberStart: number, classContextId: number): void {
// otherwise something static
state.tokens[state.tokens.length - 1].type = tt._static;
isStatic = true;

if (match(tt.braceL)) {
// This is a static block. Mark the word "static" with the class context ID for class element
// detection and parse as a regular block.
state.tokens[state.tokens.length - 1].contextId = classContextId;
parseBlock();
return;
}
}

parseClassMemberWithIsStatic(memberStart, isStatic, classContextId);
Expand Down
34 changes: 25 additions & 9 deletions src/util/getClassInfo.ts
Expand Up @@ -85,25 +85,24 @@ export default function getClassInfo(
}
tokens.nextToken();
}
if (isStatic && tokens.matches1(tt.braceL)) {
// This is a static block, so don't process it in any special way.
skipToNextClassElement(tokens, classContextId);
continue;
}
if (
tokens.matchesContextual(ContextualKeyword._constructor) &&
!tokens.currentToken().isType
) {
({constructorInitializerStatements, constructorInsertPos} = processConstructor(tokens));
continue;
}

const nameStartIndex = tokens.currentIndex();
skipFieldName(tokens);
if (tokens.matches1(tt.lessThan) || tokens.matches1(tt.parenL)) {
// This is a method, so just skip to the next method/field. To do that, we seek forward to
// the next start of a class name (either an open bracket or an identifier, or the closing
// curly brace), then seek backward to include any access modifiers.
while (tokens.currentToken().contextId !== classContextId) {
tokens.nextToken();
}
while (isAccessModifier(tokens.tokenAtRelativeIndex(-1))) {
tokens.previousToken();
}
// This is a method, so nothing to process.
skipToNextClassElement(tokens, classContextId);
continue;
}
// There might be a type annotation that we need to skip.
Expand Down Expand Up @@ -155,6 +154,23 @@ export default function getClassInfo(
};
}

/**
* Move the token processor to the next method/field in the class.
*
* To do that, we seek forward to the next start of a class name (either an open
* bracket or an identifier, or the closing curly brace), then seek backward to
* include any access modifiers.
*/
function skipToNextClassElement(tokens: TokenProcessor, classContextId: number): void {
tokens.nextToken();
while (tokens.currentToken().contextId !== classContextId) {
tokens.nextToken();
}
while (isAccessModifier(tokens.tokenAtRelativeIndex(-1))) {
tokens.previousToken();
}
}

function processClassHeader(tokens: TokenProcessor): ClassHeaderInfo {
const classToken = tokens.currentToken();
const contextId = classToken.contextId;
Expand Down
54 changes: 54 additions & 0 deletions test/sucrase-test.ts
Expand Up @@ -1179,4 +1179,58 @@ describe("sucrase", () => {
{transforms: []},
);
});

it("parses and passes through class static blocks", () => {
assertResult(
`
class A {
static {
console.log("Initialized the class");
}
static foo() {
return 3;
}
}
`,
`
class A {
static {
console.log("Initialized the class");
}
static foo() {
return 3;
}
}
`,
{transforms: []},
);
});

it("correctly handles scope analysis within static blocks", () => {
assertResult(
`
import {x, y, z} from './foo';
class A {
static {
const x = 3;
console.log(x);
console.log(y);
}
}
`,
`
import { y,} from './foo';
class A {
static {
const x = 3;
console.log(x);
console.log(y);
}
}
`,
{transforms: ["typescript"]},
);
});
});

0 comments on commit 2c53710

Please sign in to comment.