Skip to content

Commit

Permalink
Improve plugins typings (Part 2) (#14639)
Browse files Browse the repository at this point in the history
* exponentiation-operator

* duplicate-keys

* computed-properties

* replace-supers

* block-scoping

* block-scoped-functions

* syntax-typescript

* record-and-tuple

* private-property-in-object

* partial-application

* json-strings

* function-sent

* function-bind

* class-static-block

* async-generator-functions

* Update packages/babel-plugin-transform-block-scoping/src/index.ts

* address review comments

* helper-replace-supers
  • Loading branch information
JLHwung committed Jun 18, 2022
1 parent 9a69ece commit 0d7a7ef
Show file tree
Hide file tree
Showing 18 changed files with 375 additions and 199 deletions.
Expand Up @@ -3,7 +3,13 @@ import { assignmentExpression, sequenceExpression } from "@babel/types";
import type { Visitor } from "@babel/traverse";
import type * as t from "@babel/types";

export default function (opts: { build: Function; operator: string }) {
export default function (opts: {
build: (
left: t.Expression | t.PrivateName,
right: t.Expression,
) => t.Expression;
operator: t.BinaryExpression["operator"];
}) {
const { build, operator } = opts;

const visitor: Visitor = {
Expand All @@ -12,7 +18,7 @@ export default function (opts: { build: Function; operator: string }) {
if (node.operator !== operator + "=") return;

const nodes: t.AssignmentExpression[] = [];
// @ts-expect-error todo(flow->ts)
// @ts-expect-error Fixme: node.left can be a TSAsExpression
const exploded = explode(node.left, nodes, this, scope);
nodes.push(
assignmentExpression(
Expand Down
Expand Up @@ -25,7 +25,7 @@ import type * as t from "@babel/types";
import { willPathCastToBoolean } from "./util";

class AssignmentMemoiser {
private _map: WeakMap<t.Expression, { count: number; value: t.LVal }>;
private _map: WeakMap<t.Expression, { count: number; value: t.Identifier }>;
constructor() {
this._map = new WeakMap();
}
Expand All @@ -49,7 +49,7 @@ class AssignmentMemoiser {
return value;
}

set(key: t.Expression, value: t.LVal, count: number) {
set(key: t.Expression, value: t.Identifier, count: number) {
return this._map.set(key, { count, value });
}
}
Expand All @@ -66,11 +66,12 @@ function toNonOptional(
if (path.isOptionalCallExpression()) {
const callee = path.get("callee");
if (path.node.optional && callee.isOptionalMemberExpression()) {
const { object } = callee.node;
const context = path.scope.maybeGenerateMemoised(object) || object;
// object must be a conditional expression because the optional private access in object has been transformed
const object = callee.node.object as t.ConditionalExpression;
const context = path.scope.maybeGenerateMemoised(object);
callee
.get("object")
.replaceWith(assignmentExpression("=", context as t.LVal, object));
.replaceWith(assignmentExpression("=", context, object));

return callExpression(memberExpression(base, identifier("call")), [
context,
Expand Down
84 changes: 62 additions & 22 deletions packages/babel-helper-replace-supers/src/index.ts
Expand Up @@ -24,6 +24,12 @@ export {
skipAllButComputedKey,
} from "@babel/helper-environment-visitor";

type ThisRef =
| {
memo: t.AssignmentExpression;
this: t.Identifier;
}
| { this: t.ThisExpression };
/**
* Creates an expression which result is the proto of objectRef.
*
Expand All @@ -35,7 +41,12 @@ export {
*
* helpers.getPrototypeOf(CLASS.prototype)
*/
function getPrototypeOfExpression(objectRef, isStatic, file, isPrivateMethod) {
function getPrototypeOfExpression(
objectRef: t.Identifier,
isStatic: boolean,
file: File,
isPrivateMethod: boolean,
) {
objectRef = cloneNode(objectRef);
const targetRef =
isStatic || isPrivateMethod
Expand Down Expand Up @@ -79,8 +90,8 @@ type SharedState = {
isDerivedConstructor: boolean;
isStatic: boolean;
isPrivateMethod: boolean;
getObjectRef: Function;
getSuperRef: Function;
getObjectRef: () => t.Identifier;
getSuperRef: () => t.Identifier;
// we dont need boundGet here, but memberExpressionToFunctions handler needs it.
boundGet: HandlerState["get"];
};
Expand All @@ -93,11 +104,25 @@ type SuperMember = NodePath<
}
>;

const specHandlers = {
interface SpecHandler
extends Pick<
Handler,
"get" | "set" | "destructureSet" | "call" | "optionalCall" | "memoise"
> {
_get(
this: Handler & SpecHandler,
superMember: SuperMember,
thisRefs: ThisRef,
): t.CallExpression;
_getThisRefs(): ThisRef;
prop(this: Handler & SpecHandler, superMember: SuperMember): t.Expression;
}

const specHandlers: SpecHandler = {
memoise(
this: Handler & typeof specHandlers,
this: Handler & SpecHandler,
superMember: SuperMember,
count,
count: number,
) {
const { scope, node } = superMember;
const { computed, property } = node;
Expand All @@ -113,7 +138,7 @@ const specHandlers = {
this.memoiser.set(property, memo, count);
},

prop(this: Handler & typeof specHandlers, superMember: SuperMember) {
prop(this: Handler & SpecHandler, superMember: SuperMember) {
const { computed, property } = superMember.node;
if (this.memoiser.has(property)) {
return cloneNode(this.memoiser.get(property));
Expand All @@ -126,14 +151,14 @@ const specHandlers = {
return stringLiteral((property as t.Identifier).name);
},

get(this: Handler & typeof specHandlers, superMember: SuperMember) {
get(this: Handler & SpecHandler, superMember: SuperMember) {
return this._get(superMember, this._getThisRefs());
},

_get(
this: Handler & typeof specHandlers,
this: Handler & SpecHandler,
superMember: SuperMember,
thisRefs,
thisRefs: ThisRef,
) {
const proto = getPrototypeOfExpression(
this.getObjectRef(),
Expand All @@ -142,13 +167,14 @@ const specHandlers = {
this.isPrivateMethod,
);
return callExpression(this.file.addHelper("get"), [
// @ts-ignore memo does not exist when this.isDerivedConstructor is false
thisRefs.memo ? sequenceExpression([thisRefs.memo, proto]) : proto,
this.prop(superMember),
thisRefs.this,
]);
},

_getThisRefs(this: Handler & typeof specHandlers) {
_getThisRefs(this: Handler & SpecHandler): ThisRef {
if (!this.isDerivedConstructor) {
return { this: thisExpression() };
}
Expand All @@ -159,7 +185,11 @@ const specHandlers = {
};
},

set(this: Handler & typeof specHandlers, superMember: SuperMember, value) {
set(
this: Handler & SpecHandler,
superMember: SuperMember,
value: t.Expression,
) {
const thisRefs = this._getThisRefs();
const proto = getPrototypeOfExpression(
this.getObjectRef(),
Expand All @@ -168,6 +198,7 @@ const specHandlers = {
this.isPrivateMethod,
);
return callExpression(this.file.addHelper("set"), [
// @ts-ignore memo does not exist when this.isDerivedConstructor is false
thisRefs.memo ? sequenceExpression([thisRefs.memo, proto]) : proto,
this.prop(superMember),
value,
Expand All @@ -176,16 +207,17 @@ const specHandlers = {
]);
},

destructureSet(
this: Handler & typeof specHandlers,
superMember: SuperMember,
) {
destructureSet(this: Handler & SpecHandler, superMember: SuperMember) {
throw superMember.buildCodeFrameError(
`Destructuring to a super field is not supported yet.`,
);
},

call(this: Handler & typeof specHandlers, superMember: SuperMember, args) {
call(
this: Handler & SpecHandler,
superMember: SuperMember,
args: t.CallExpression["arguments"],
) {
const thisRefs = this._getThisRefs();
return optimiseCall(
this._get(superMember, thisRefs),
Expand All @@ -196,9 +228,9 @@ const specHandlers = {
},

optionalCall(
this: Handler & typeof specHandlers,
this: Handler & SpecHandler,
superMember: SuperMember,
args,
args: t.CallExpression["arguments"],
) {
const thisRefs = this._getThisRefs();
return optimiseCall(
Expand Down Expand Up @@ -242,7 +274,11 @@ const looseHandlers = {
return memberExpression(object, prop, computed);
},

set(this: Handler & typeof specHandlers, superMember: SuperMember, value) {
set(
this: Handler & typeof specHandlers,
superMember: SuperMember,
value: t.Expression,
) {
const { computed } = superMember.node;
const prop = this.prop(superMember);

Expand All @@ -263,14 +299,18 @@ const looseHandlers = {
return memberExpression(thisExpression(), prop, computed);
},

call(this: Handler & typeof specHandlers, superMember: SuperMember, args) {
call(
this: Handler & typeof specHandlers,
superMember: SuperMember,
args: t.CallExpression["arguments"],
) {
return optimiseCall(this.get(superMember), thisExpression(), args, false);
},

optionalCall(
this: Handler & typeof specHandlers,
superMember: SuperMember,
args,
args: t.CallExpression["arguments"],
) {
return optimiseCall(this.get(superMember), thisExpression(), args, true);
},
Expand Down
@@ -1,4 +1,5 @@
import { types as t, template } from "@babel/core";
import type { NodePath } from "@babel/traverse";

const buildForAwait = template(`
async function wrapper() {
Expand Down Expand Up @@ -29,7 +30,10 @@ const buildForAwait = template(`
}
`);

export default function (path, { getAsyncIterator }) {
export default function (
path: NodePath<t.ForOfStatement>,
{ getAsyncIterator }: { getAsyncIterator: t.Identifier },
) {
const { node, scope, parent } = path;

const stepKey = scope.generateUidIdentifier("step");
Expand Down
@@ -1,5 +1,6 @@
import { declare } from "@babel/helper-plugin-utils";
import syntaxClassStaticBlock from "@babel/plugin-syntax-class-static-block";
import type { Scope } from "@babel/traverse";

import {
enableFeature,
Expand All @@ -10,11 +11,11 @@ import type * as t from "@babel/types";
/**
* Generate a uid that is not in `denyList`
*
* @param {*} scope
* @param {Scope} scope
* @param {Set<string>} denyList a deny list that the generated uid should avoid
* @returns
*/
function generateUid(scope, denyList: Set<string>) {
function generateUid(scope: Scope, denyList: Set<string>) {
const name = "";
let uid;
let i = 1;
Expand Down
14 changes: 10 additions & 4 deletions packages/babel-plugin-proposal-function-bind/src/index.ts
@@ -1,27 +1,31 @@
import { declare } from "@babel/helper-plugin-utils";
import syntaxFunctionBind from "@babel/plugin-syntax-function-bind";
import { types as t } from "@babel/core";
import type { Scope } from "@babel/traverse";

export default declare(api => {
api.assertVersion(7);

function getTempId(scope) {
function getTempId(scope: Scope) {
let id = scope.path.getData("functionBind");
if (id) return t.cloneNode(id);

id = scope.generateDeclaredUidIdentifier("context");
return scope.path.setData("functionBind", id);
}

function getStaticContext(bind, scope) {
const object = bind.object || bind.callee.object;
function getStaticContext(bind: t.BindExpression, scope: Scope) {
const object =
bind.object ||
// @ts-ignore Fixme: should check bind.callee type first
bind.callee.object;
return (
scope.isStatic(object) &&
(t.isSuper(object) ? t.thisExpression() : object)
);
}

function inferBindContext(bind, scope) {
function inferBindContext(bind: t.BindExpression, scope: Scope) {
const staticContext = getStaticContext(bind, scope);
if (staticContext) return t.cloneNode(staticContext);

Expand All @@ -32,9 +36,11 @@ export default declare(api => {
bind.callee,
]);
} else {
// @ts-ignore Fixme: should check bind.callee type first
bind.callee.object = t.assignmentExpression(
"=",
tempId,
// @ts-ignore Fixme: should check bind.callee type first
bind.callee.object,
);
}
Expand Down
7 changes: 5 additions & 2 deletions packages/babel-plugin-proposal-function-sent/src/index.ts
Expand Up @@ -7,11 +7,14 @@ import type { Visitor } from "@babel/traverse";
export default declare(api => {
api.assertVersion(7);

const isFunctionSent = node =>
const isFunctionSent = (node: t.MetaProperty) =>
t.isIdentifier(node.meta, { name: "function" }) &&
t.isIdentifier(node.property, { name: "sent" });

const hasBeenReplaced = (node, sentId) =>
const hasBeenReplaced = (
node: t.Node,
sentId: string,
): node is t.AssignmentExpression =>
t.isAssignmentExpression(node) &&
t.isIdentifier(node.left, { name: sentId });

Expand Down
2 changes: 1 addition & 1 deletion packages/babel-plugin-proposal-json-strings/src/index.ts
Expand Up @@ -6,7 +6,7 @@ import type { NodePath } from "@babel/traverse";
export default declare(api => {
api.assertVersion(7);
const regex = /(\\*)([\u2028\u2029])/g;
function replace(match, escapes, separator) {
function replace(match: string, escapes: string, separator: string) {
// If there's an odd number, that means the separator itself was escaped.
// "\X" escapes X.
// "\\X" escapes the backslash, so X is unescaped.
Expand Down

0 comments on commit 0d7a7ef

Please sign in to comment.