Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

babel parser type improvements #14801

Merged
merged 6 commits into from Aug 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/babel-parser/src/index.ts
Expand Up @@ -113,6 +113,7 @@ function getParserClass(pluginsFromOptions: PluginList): {
if (!cls) {
cls = Parser;
for (const plugin of pluginList) {
// @ts-expect-error todo(flow->ts)
cls = mixinPlugins[plugin](cls);
}
parserClassCache[key] = cls;
Expand Down
5 changes: 4 additions & 1 deletion packages/babel-parser/src/parser/comments.ts
Expand Up @@ -66,7 +66,10 @@ function setLeadingComments(node: Undone<Node>, comments: Array<Comment>) {
* @param {Undone<Node>} node
* @param {Array<Comment>} comments
*/
export function setInnerComments(node: Undone<Node>, comments: Array<Comment>) {
export function setInnerComments(
node: Undone<Node>,
comments?: Array<Comment>,
) {
if (node.innerComments === undefined) {
node.innerComments = comments;
} else {
Expand Down
49 changes: 26 additions & 23 deletions packages/babel-parser/src/parser/expression.ts
Expand Up @@ -60,6 +60,7 @@ import {
PARAM_RETURN,
functionFlags,
} from "../util/production-parameter";
import type { ParamKind } from "../util/production-parameter";
import {
newArrowHeadScope,
newAsyncArrowScope,
Expand All @@ -71,44 +72,44 @@ import { setInnerComments } from "./comments";
import { cloneIdentifier, type Undone } from "./node";
import type Parser from ".";

/*::
import type { SourceType } from "../options";
declare var invariant;
*/

export default class ExpressionParser extends LValParser {
export default abstract class ExpressionParser extends LValParser {
// Forward-declaration: defined in statement.js
/*::
+parseBlock: (
abstract parseBlock(
allowDirectives?: boolean,
createNewLexicalScope?: boolean,
afterBlockParse?: (hasStrictModeDirective: boolean) => void,
) => N.BlockStatement;
+parseClass: (
): N.BlockStatement;
abstract parseClass(
node: N.Class,
isStatement: boolean,
optionalId?: boolean,
) => N.Class;
+parseDecorators: (allowExport?: boolean) => void;
+parseFunction: <T: N.NormalFunction>(
): N.Class;
abstract parseDecorators(allowExport?: boolean): void;
abstract parseFunction<T extends N.NormalFunction>(
node: T,
statement?: number,
allowExpressionBody?: boolean,
isAsync?: boolean,
) => T;
+parseFunctionParams: (node: N.Function, allowModifiers?: boolean) => void;
+takeDecorators: (node: N.HasDecorators) => void;
+parseBlockOrModuleBlockBody: (
): T;
abstract parseFunctionParams(
node: N.Function,
allowModifiers?: boolean,
): void;
abstract takeDecorators(node: N.HasDecorators): void;
abstract parseBlockOrModuleBlockBody(
body: N.Statement[],
directives: ?(N.Directive[]),
directives: N.Directive[] | null | undefined,
topLevel: boolean,
end: TokenType,
afterBlockParse?: (hasStrictModeDirective: boolean) => void
) => void
+parseProgram: (
program: N.Program, end: TokenType, sourceType?: SourceType
) => N.Program
*/
afterBlockParse?: (hasStrictModeDirective: boolean) => void,
): void;
abstract parseProgram(
program: N.Program,
end: TokenType,
sourceType?: SourceType,
): N.Program;

// For object literal, check if property __proto__ has been used more than once.
// If the expression is a destructuring assignment, then __proto__ may appear
Expand Down Expand Up @@ -2629,7 +2630,9 @@ export default class ExpressionParser extends LValParser {

// FunctionBody[Yield, Await]:
// StatementList[?Yield, ?Await, +Return] opt
this.prodParam.enter(this.prodParam.currentFlags() | PARAM_RETURN);
this.prodParam.enter(
(this.prodParam.currentFlags() | PARAM_RETURN) as ParamKind,
);
node.body = this.parseBlock(
true,
false,
Expand Down
19 changes: 9 additions & 10 deletions packages/babel-parser/src/parser/index.ts
@@ -1,5 +1,5 @@
import type { Options } from "../options";
import type { File, Program /*::, JSXOpeningElement */ } from "../types";
import type * as N from "../types";
import type { PluginList } from "../plugin-utils";
import { getOptions } from "../options";
import StatementParser from "./statement";
Expand All @@ -14,11 +14,10 @@ export type PluginsMap = Map<

export default class Parser extends StatementParser {
// Forward-declaration so typescript plugin can override jsx plugin
/*::
+jsxParseOpeningElementAfterName: (
node: JSXOpeningElement,
) => JSXOpeningElement;
*/
// todo(flow->ts) - this probably can be removed
// abstract jsxParseOpeningElementAfterName(
// node: N.JSXOpeningElement,
// ): N.JSXOpeningElement;

constructor(options: Options | undefined | null, input: string) {
options = getOptions(options);
Expand All @@ -32,15 +31,15 @@ export default class Parser extends StatementParser {

// This can be overwritten, for example, by the TypeScript plugin.
getScopeHandler(): {
new (...args: any): ScopeHandler<any>;
new (...args: any): ScopeHandler;
} {
return ScopeHandler;
}

parse(): File {
parse(): N.File {
this.enterInitialScopes();
const file = this.startNode() as File;
const program = this.startNode() as Program;
const file = this.startNode() as N.File;
const program = this.startNode() as N.Program;
this.nextToken();
file.errors = null;
this.parseTopLevel(file, program);
Expand Down
62 changes: 32 additions & 30 deletions packages/babel-parser/src/parser/lval.ts
@@ -1,4 +1,3 @@
/*:: declare var invariant; */
import * as charCodes from "charcodes";
import { tt, type TokenType } from "../tokenizer/types";
import type {
Expand All @@ -11,18 +10,17 @@ import type {
Pattern,
RestElement,
SpreadElement,
/*:: ObjectOrClassMember, */
/*:: ClassMember, */
ObjectOrClassMember,
ClassMember,
ObjectMember,
TsNamedTypeElementBase,
PrivateName,
ObjectExpression,
ObjectPattern,
ArrayExpression,
ArrayPattern,
/*:: TsNamedTypeElementBase, */
/*:: PrivateName, */
/*:: ObjectExpression, */
/*:: ObjectPattern, */
} from "../types";
import type { Position } from "../util/location";
import type { Pos, Position } from "../util/location";
import {
isStrictBindOnlyReservedWord,
isStrictBindReservedWord,
Expand All @@ -46,39 +44,43 @@ const unwrapParenthesizedExpression = (node: Node): Node => {
: node;
};

export default class LValParser extends NodeUtils {
export default abstract class LValParser extends NodeUtils {
// Forward-declaration: defined in expression.js
/*::
+parseIdentifier: (liberal?: boolean) => Identifier;
+parseMaybeAssignAllowIn: (
refExpressionErrors?: ?ExpressionErrors,
abstract parseIdentifier(liberal?: boolean): Identifier;
abstract parseMaybeAssign(
refExpressionErrors?: ExpressionErrors | null,
afterLeftParse?: Function,
refNeedsArrowPos?: Pos | null,
): Expression;

abstract parseMaybeAssignAllowIn(
refExpressionErrors?: ExpressionErrors | null,
afterLeftParse?: Function,
) => Expression;
+parseObjectLike: <T: ObjectPattern | ObjectExpression>(
refNeedsArrowPos?: Pos | null,
): Expression;

abstract parseObjectLike<T extends ObjectPattern | ObjectExpression>(
close: TokenType,
isPattern: boolean,
isRecord?: ?boolean,
refExpressionErrors?: ?ExpressionErrors,
) => T;
+parseObjPropValue: (
isRecord?: boolean,
refExpressionErrors?: ExpressionErrors,
): T;
abstract parseObjPropValue(
prop: any,
startPos: ?number,
startLoc: ?Position,
startPos: number | null,
startLoc: Position | null,
isGenerator: boolean,
isAsync: boolean,
isPattern: boolean,
isAccessor: boolean,
refExpressionErrors?: ?ExpressionErrors,
) => void;
+parsePropertyName: (
refExpressionErrors?: ExpressionErrors | null,
): void;
abstract parsePropertyName(
prop: ObjectOrClassMember | ClassMember | TsNamedTypeElementBase,
) => Expression | Identifier;
+parsePrivateName: () => PrivateName
*/
): Expression | Identifier;
abstract parsePrivateName(): PrivateName;
// Forward-declaration: defined in statement.js
/*::
+parseDecorator: () => Decorator;
*/
abstract parseDecorator(): Decorator;

/**
* Convert existing expression atom to assignable pattern
Expand Down
2 changes: 1 addition & 1 deletion packages/babel-parser/src/parser/node.ts
Expand Up @@ -98,7 +98,7 @@ export function cloneStringLiteral(node: any): any {

export type Undone<T extends NodeType> = Omit<T, "type">;

export class NodeUtils extends UtilParser {
export abstract class NodeUtils extends UtilParser {
startNode<T extends NodeType>(): Undone<T> {
// @ts-expect-error
return new Node(this, this.state.start, this.state.startLoc);
Expand Down
17 changes: 6 additions & 11 deletions packages/babel-parser/src/parser/statement.ts
Expand Up @@ -184,7 +184,7 @@ function babel7CompatTokens(tokens: (Token | N.Comment)[], input: string) {
}
return tokens;
}
export default class StatementParser extends ExpressionParser {
export default abstract class StatementParser extends ExpressionParser {
// ### Statement parsing

// Parse a program. Initializes the parser, reads any number of
Expand Down Expand Up @@ -1627,16 +1627,11 @@ export default class StatementParser extends ExpressionParser {
state: N.ParseClassMemberState,
isStatic: boolean,
) {
// @ts-expect-error: Fixme: convert $FlowSubtype to TS
const publicMethod: $FlowSubtype<N.ClassMethod> = member;
// @ts-expect-error: Fixme: convert $FlowSubtype to TS
const privateMethod: $FlowSubtype<N.ClassPrivateMethod> = member;
// @ts-expect-error: Fixme: convert $FlowSubtype to TS
const publicProp: $FlowSubtype<N.ClassProperty> = member;
// @ts-expect-error: Fixme: convert $FlowSubtype to TS
const privateProp: $FlowSubtype<N.ClassPrivateProperty> = member;
// @ts-expect-error: Fixme: convert $FlowSubtype to TS
const accessorProp: $FlowSubtype<N.ClassAccessorProperty> = member;
const publicMethod = member as N.ClassMethod;
const privateMethod = member as N.ClassPrivateMethod;
const publicProp = member as N.ClassProperty;
const privateProp = member as N.ClassPrivateProperty;
const accessorProp = member as N.ClassAccessorProperty;

const method: typeof publicMethod | typeof privateMethod = publicMethod;
const publicMember: typeof publicMethod | typeof publicProp = publicMethod;
Expand Down
8 changes: 2 additions & 6 deletions packages/babel-parser/src/parser/util.ts
Expand Up @@ -23,9 +23,7 @@ import {
} from "../parse-error";
import type Parser from ".";

/*::
import type ScopeHandler from "../util/scope";
*/

type TryParse<Node, Error, Thrown, Aborted, FailState> = {
node: Node;
Expand All @@ -37,11 +35,9 @@ type TryParse<Node, Error, Thrown, Aborted, FailState> = {

// ## Parser utilities

export default class UtilParser extends Tokenizer {
export default abstract class UtilParser extends Tokenizer {
// Forward-declaration: defined in parser/index.js
/*::
+getScopeHandler: () => Class<ScopeHandler<*>>;
*/
abstract getScopeHandler(): { new (...args: any): ScopeHandler };

// TODO

Expand Down
4 changes: 1 addition & 3 deletions packages/babel-parser/src/plugin-utils.ts
Expand Up @@ -220,9 +220,7 @@ import placeholders from "./plugins/placeholders";
import v8intrinsic from "./plugins/v8intrinsic";

// NOTE: order is important. estree must come first; placeholders must come last.
export const mixinPlugins: {
[name: string]: MixinPlugin;
} = {
export const mixinPlugins = {
estree,
jsx,
flow,
Expand Down
36 changes: 19 additions & 17 deletions packages/babel-parser/src/plugins/estree.ts
Expand Up @@ -19,13 +19,8 @@ function toESTreeLocation(node: any) {
return node;
}

export default (superClass: {
new (...args: any): Parser;
}): {
new (...args: any): Parser;
} =>
// @ts-expect-error plugin may override interfaces
class extends superClass {
export default (superClass: typeof Parser) =>
class ESTreeParserMixin extends superClass implements Parser {
parse(): File {
const file = toESTreeLocation(super.parse());

Expand Down Expand Up @@ -124,7 +119,11 @@ export default (superClass: {
// @ts-expect-error N.Directive.value is not defined
stmt.directive = directiveLiteral.extra.raw.slice(1, -1);

return this.finishNodeAt(stmt, "ExpressionStatement", directive.loc.end);
return this.finishNodeAt(
stmt,
"ExpressionStatement",
directive.loc.end,
) as N.ExpressionStatement;
}

// ==================================
Expand Down Expand Up @@ -164,15 +163,18 @@ export default (superClass: {

parseBlockBody(
node: N.BlockStatementLike,
...args: [
boolean | undefined | null,
boolean,
TokenType,
void | ((a: boolean) => void),
]
allowDirectives: boolean | undefined | null,
topLevel: boolean,
end: TokenType,
afterBlockParse?: (hasStrictModeDirective: boolean) => void,
): void {
// @ts-expect-error figure out args typings
super.parseBlockBody(node, ...args);
super.parseBlockBody(
node,
allowDirectives,
topLevel,
end,
afterBlockParse,
);

const directiveStatements = node.directives.map(d =>
this.directiveToStmt(d),
Expand Down Expand Up @@ -486,7 +488,7 @@ export default (superClass: {
break;
}

return node;
return node as N.AnyExport;
}

parseSubscript(
Expand Down