Add TS support to @babel/parser's Scope (#9766)

* [parser] Allow plugins to extend ScopeHandler

* Directly extend Scope

* Don't use new.target to get the ScopeHandler

* [parser] Add TS enum  support to the Scope

* Remove duplicated options in tests

* Fix

* Fix flow

* Rename tests

* Add tests

* Full typescript support in scope

* Remove BIND_SIMPLE_CATCH

SCOPE_SIMPLE_CATCH was used instead

* Export TS types

* Register function declarations

* Fix body-less functions and namespaces

1) Move this.scope.exit() for functions from parseFunctionBody to the callers.
    Otherwise the scope of body-less functions was never closed.
    Also, it is easier to track scope.exit() if it is near to scope.enter()
2) Register namespace ids for export

* Disallow redeclaration of enum with const enum
This commit is contained in:
Nicolò Ribaudo
2019-04-26 14:19:53 +02:00
committed by GitHub
parent 293f3c98d2
commit 30d507c915
108 changed files with 3974 additions and 98 deletions

View File

@@ -11,7 +11,7 @@ import {
import { lineBreak, skipWhiteSpace } from "../util/whitespace";
import * as charCodes from "charcodes";
import {
BIND_SIMPLE_CATCH,
BIND_CLASS,
BIND_LEXICAL,
BIND_VAR,
BIND_FUNCTION,
@@ -662,12 +662,7 @@ export default class StatementParser extends ExpressionParser {
clause.param = this.parseBindingAtom();
const simple = clause.param.type === "Identifier";
this.scope.enter(simple ? SCOPE_SIMPLE_CATCH : 0);
this.checkLVal(
clause.param,
simple ? BIND_SIMPLE_CATCH : BIND_LEXICAL,
null,
"catch clause",
);
this.checkLVal(clause.param, BIND_LEXICAL, null, "catch clause");
this.expect(tt.parenR);
} else {
clause.param = null;
@@ -1056,22 +1051,6 @@ export default class StatementParser extends ExpressionParser {
if (isStatement) {
node.id = this.parseFunctionId(requireId);
if (node.id && !isHangingStatement) {
// If it is a regular function declaration in sloppy mode, then it is
// subject to Annex B semantics (BIND_FUNCTION). Otherwise, the binding
// mode depends on properties of the current scope (see
// treatFunctionsAsVar).
this.checkLVal(
node.id,
this.state.strict || node.generator || node.async
? this.scope.treatFunctionsAsVar
? BIND_VAR
: BIND_LEXICAL
: BIND_FUNCTION,
null,
"function name",
);
}
}
const oldInClassProperty = this.state.inClassProperty;
@@ -1099,6 +1078,15 @@ export default class StatementParser extends ExpressionParser {
);
});
this.scope.exit();
if (isStatement && !isHangingStatement) {
// We need to validate this _after_ parsing the function body
// because of TypeScript body-less function declarations,
// which shouldn't be added to the scope.
this.checkFunctionStatementId(node);
}
this.state.inClassProperty = oldInClassProperty;
this.state.yieldPos = oldYieldPos;
this.state.awaitPos = oldAwaitPos;
@@ -1125,6 +1113,25 @@ export default class StatementParser extends ExpressionParser {
this.checkYieldAwaitInDefaultParams();
}
checkFunctionStatementId(node: N.Function): void {
if (!node.id) return;
// If it is a regular function declaration in sloppy mode, then it is
// subject to Annex B semantics (BIND_FUNCTION). Otherwise, the binding
// mode depends on properties of the current scope (see
// treatFunctionsAsVar).
this.checkLVal(
node.id,
this.state.strict || node.generator || node.async
? this.scope.treatFunctionsAsVar
? BIND_VAR
: BIND_LEXICAL
: BIND_FUNCTION,
null,
"function name",
);
}
// Parse a class declaration or literal (depending on the
// `isStatement` parameter).
@@ -1612,7 +1619,7 @@ export default class StatementParser extends ExpressionParser {
if (this.match(tt.name)) {
node.id = this.parseIdentifier();
if (isStatement) {
this.checkLVal(node.id, BIND_LEXICAL, undefined, "class name");
this.checkLVal(node.id, BIND_CLASS, undefined, "class name");
}
} else {
if (optionalId || !isStatement) {