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

Improve @babel/helper-* typings #14620

Merged
merged 14 commits into from May 31, 2022
4 changes: 3 additions & 1 deletion packages/babel-helper-annotate-as-pure/src/index.ts
Expand Up @@ -10,7 +10,9 @@ const isPureAnnotated = ({ leadingComments }: Node): boolean =>
export default function annotateAsPure(
pathOrNode: Node | { node: Node },
): void {
const node = pathOrNode["node"] || pathOrNode;
const node =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it correctly inferred as Node?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope. I have to cast it as a Node.

// @ts-expect-error Node will not have `node` property
pathOrNode["node"] || pathOrNode;
if (isPureAnnotated(node)) {
return;
}
Expand Down
@@ -1,6 +1,7 @@
import explode from "@babel/helper-explode-assignable-expression";
import { assignmentExpression, sequenceExpression } from "@babel/types";
import type { Visitor } from "@babel/traverse";
import * as t from "@babel/types";
JLHwung marked this conversation as resolved.
Show resolved Hide resolved

export default function (opts: { build: Function; operator: string }) {
const { build, operator } = opts;
Expand All @@ -10,7 +11,7 @@ export default function (opts: { build: Function; operator: string }) {
const { node, scope } = path;
if (node.operator !== operator + "=") return;

const nodes = [];
const nodes: t.AssignmentExpression[] = [];
// @ts-expect-error todo(flow->ts)
const exploded = explode(node.left, nodes, this, scope);
nodes.push(
Expand Down
15 changes: 11 additions & 4 deletions packages/babel-helper-check-duplicate-nodes/src/index.ts
@@ -1,20 +1,25 @@
import { VISITOR_KEYS } from "@babel/types";
import type * as t from "@babel/types";

export default function checkDuplicateNodes(ast) {
type StackItem = {
node: t.Node;
parent: t.Node | null;
};
export default function checkDuplicateNodes(ast: t.Node) {
if (arguments.length !== 1) {
throw new Error("checkDuplicateNodes accepts only one argument: ast");
}
// A Map from node to its parent
const parentsMap = new Map();

const hidePrivateProperties = (key, val) => {
const hidePrivateProperties = (key: string, val: unknown) => {
// Hides properties like _shadowedFunctionLiteral,
// which makes the AST circular
if (key[0] === "_") return "[Private]";
return val;
};

const stack = [{ node: ast, parent: null }];
const stack: StackItem[] = [{ node: ast, parent: null }];
let item;

while ((item = stack.pop()) !== undefined) {
Expand All @@ -36,7 +41,9 @@ export default function checkDuplicateNodes(ast) {
parentsMap.set(node, parent);

for (const key of keys) {
const subNode = node[key];
const subNode =
// @ts-expect-error visitor keys must present in node
node[key];

if (Array.isArray(subNode)) {
for (const child of subNode) {
Expand Down
36 changes: 31 additions & 5 deletions packages/babel-helper-define-map/src/index.ts
Expand Up @@ -17,8 +17,11 @@ import {
toComputedKey,
toKeyAlias,
} from "@babel/types";
import type { File } from "@babel/core";
import type * as t from "@babel/types";
import type { Scope } from "@babel/traverse";

function toKind(node: any) {
function toKind(node: t.Property | t.Method) {
if (isClassMethod(node) || isObjectMethod(node)) {
if (node.kind === "get" || node.kind === "set") {
return node.kind;
Expand All @@ -30,12 +33,32 @@ function toKind(node: any) {

const has = Function.prototype.call.bind(Object.prototype.hasOwnProperty);

export function push(mutatorMap: any, node: any, kind: string, file, scope?) {
type DefineMap = {
decorators: t.ArrayExpression;
_computed: boolean;
_inherits: t.Node[];
_key: t.Expression | t.PrivateName;
value?: t.Expression;
initializer?: t.Expression;
get?: t.Expression;
set?: t.Expression;
kind: "get" | "set" | "value" | "initializer";
};

export type MutatorMap = Record<string, DefineMap>;

export function push(
mutatorMap: MutatorMap,
node: t.Property | t.Method,
kind: DefineMap["kind"],
file: File,
scope?: Scope,
) {
const alias = toKeyAlias(node);

//

let map = {} as any;
let map = {} as DefineMap;
if (has(mutatorMap, alias)) map = mutatorMap[alias];
mutatorMap[alias] = map;

Expand All @@ -46,7 +69,10 @@ export function push(mutatorMap: any, node: any, kind: string, file, scope?) {

map._key = node.key;

if (node.computed) {
if (
// @ts-expect-error computed is not in private property
node.computed
) {
map._computed = true;
}

Expand All @@ -69,7 +95,7 @@ export function push(mutatorMap: any, node: any, kind: string, file, scope?) {
}

if (isProperty(node)) {
value = node.value;
value = node.value as t.Expression;
} else if (isObjectMethod(node) || isClassMethod(node)) {
value = functionExpression(
null,
Expand Down
52 changes: 39 additions & 13 deletions packages/babel-helper-function-name/src/index.ts
Expand Up @@ -18,6 +18,7 @@ import {
toBindingIdentifierName,
} from "@babel/types";
import type * as t from "@babel/types";
import type { NodePath, Scope, Visitor } from "@babel/traverse";

function getFunctionArity(node: t.Function): number {
const count = node.params.findIndex(
Expand All @@ -26,7 +27,7 @@ function getFunctionArity(node: t.Function): number {
return count === -1 ? node.params.length : count;
}

const buildPropertyMethodAssignmentWrapper = template(`
const buildPropertyMethodAssignmentWrapper = template.statement(`
(function (FUNCTION_KEY) {
function FUNCTION_ID() {
return FUNCTION_KEY.apply(this, arguments);
Expand All @@ -40,7 +41,7 @@ const buildPropertyMethodAssignmentWrapper = template(`
})(FUNCTION)
`);

const buildGeneratorPropertyMethodAssignmentWrapper = template(`
const buildGeneratorPropertyMethodAssignmentWrapper = template.statement(`
(function (FUNCTION_KEY) {
function* FUNCTION_ID() {
return yield* FUNCTION_KEY.apply(this, arguments);
Expand All @@ -54,8 +55,18 @@ const buildGeneratorPropertyMethodAssignmentWrapper = template(`
})(FUNCTION)
`);

const visitor = {
"ReferencedIdentifier|BindingIdentifier"(path, state) {
type State = {
name: string;
outerDeclar: t.Identifier;
selfAssignment: boolean;
selfReference: boolean;
};

const visitor: Visitor<State> = {
"ReferencedIdentifier|BindingIdentifier"(
path: NodePath<t.Identifier>,
state,
) {
// check if this node matches our function id
if (path.node.name !== state.name) return;

Expand All @@ -69,7 +80,7 @@ const visitor = {
},
};

function getNameFromLiteralId(id) {
function getNameFromLiteralId(id: t.Literal) {
if (isNullLiteral(id)) {
return "null";
}
Expand All @@ -89,7 +100,12 @@ function getNameFromLiteralId(id) {
return "";
}

function wrap(state, method, id, scope) {
function wrap(
state: State,
method: t.FunctionExpression | t.ClassExpression,
id: t.Identifier,
scope: Scope,
) {
if (state.selfReference) {
if (scope.hasBinding(id.name) && !scope.hasGlobal(id.name)) {
// we can just munge the local binding
Expand Down Expand Up @@ -131,12 +147,15 @@ function wrap(state, method, id, scope) {
scope.getProgramParent().references[id.name] = true;
}

function visit(node, name, scope) {
const state = {
function visit(
node: t.FunctionExpression | t.ClassExpression,
name: string,
scope: Scope,
) {
const state: State = {
selfAssignment: false,
selfReference: false,
outerDeclar: scope.getBindingIdentifier(name),
references: [],
name: name,
};

Expand Down Expand Up @@ -188,7 +207,12 @@ export default function (
parent,
scope,
id,
}: { node: any; parent?: any; scope: any; id?: any },
}: {
node: t.FunctionExpression | t.ClassExpression;
parent?: t.Node;
scope: Scope;
id?: any;
},
localBinding = false,
supportUnicodeId = false,
) {
Expand All @@ -215,6 +239,7 @@ export default function (
) {
// always going to reference this method
node.id = cloneNode(id);
// @ts-expect-error Fixme: avoid mutating AST nodes
node.id[NOT_LOCAL_BINDING] = true;
return;
}
Expand Down Expand Up @@ -242,13 +267,14 @@ export default function (
}

name = toBindingIdentifierName(name);
id = identifier(name);
const newId = identifier(name);

// The id shouldn't be considered a local binding to the function because
// we are simply trying to set the function name and not actually create
// a local binding.
id[NOT_LOCAL_BINDING] = true;
// @ts-ignore Fixme: avoid mutating AST nodes
newId[NOT_LOCAL_BINDING] = true;

const state = visit(node, name, scope);
return wrap(state, node, id, scope) || node;
return wrap(state, node, newId, scope) || node;
}
10 changes: 5 additions & 5 deletions packages/babel-helper-hoist-variables/src/index.ts
Expand Up @@ -4,7 +4,7 @@ import {
identifier,
} from "@babel/types";
import type * as t from "@babel/types";
import type { NodePath } from "@babel/traverse";
import type { NodePath, Visitor } from "@babel/traverse";

export type EmitFunction = (
id: t.Identifier,
Expand All @@ -19,16 +19,16 @@ type State = {

type Unpacked<T> = T extends (infer U)[] ? U : T;

const visitor = {
Scope(path: NodePath, state: State) {
const visitor: Visitor<State> = {
Scope(path, state) {
if (state.kind === "let") path.skip();
},

FunctionParent(path: NodePath) {
FunctionParent(path) {
path.skip();
},

VariableDeclaration(path: NodePath<t.VariableDeclaration>, state: State) {
VariableDeclaration(path, state) {
if (state.kind && path.node.kind !== state.kind) return;

const nodes = [];
Expand Down
22 changes: 16 additions & 6 deletions packages/babel-helper-member-expression-to-functions/src/index.ts
Expand Up @@ -95,7 +95,13 @@ function isInDetachedTree(path: NodePath) {
const { parentPath, container, listKey } = path;
const parentNode = parentPath.node;
if (listKey) {
if (container !== parentNode[listKey]) return true;
if (
container !==
// @ts-expect-error listKey must be a valid parent node key
parentNode[listKey]
) {
return true;
}
} else {
if (container !== parentNode) return true;
}
Expand Down Expand Up @@ -208,10 +214,9 @@ const handle = {
);
}

const startingProp = startingOptional.isOptionalMemberExpression()
? "object"
: "callee";
const startingNode = startingOptional.node[startingProp];
const startingNode = startingOptional.isOptionalMemberExpression()
? startingOptional.node.object
: startingOptional.node.callee;
const baseNeedsMemoised = scope.maybeGenerateMemoised(startingNode);
const baseRef = baseNeedsMemoised ?? startingNode;

Expand Down Expand Up @@ -281,7 +286,12 @@ const handle = {
}

const baseMemoised = baseNeedsMemoised
? assignmentExpression("=", cloneNode(baseRef), cloneNode(startingNode))
? assignmentExpression(
"=",
// When base needs memoised, the baseRef must be an identifier
cloneNode(baseRef as t.Identifier),
cloneNode(startingNode),
)
: cloneNode(baseRef);

if (willEndPathCastToBoolean) {
Expand Down
9 changes: 5 additions & 4 deletions packages/babel-helper-remap-async-to-generator/src/index.ts
@@ -1,6 +1,6 @@
/* @noflow */

import type { NodePath } from "@babel/traverse";
import type { NodePath, Visitor } from "@babel/traverse";
import wrapFunction from "@babel/helper-wrap-function";
import annotateAsPure from "@babel/helper-annotate-as-pure";
import {
Expand All @@ -10,8 +10,9 @@ import {
isThisExpression,
yieldExpression,
} from "@babel/types";
import type * as t from "@babel/types";

const awaitVisitor = {
const awaitVisitor: Visitor<{ wrapAwait: t.Expression }> = {
Function(path) {
path.skip();
},
Expand All @@ -32,8 +33,8 @@ const awaitVisitor = {
export default function (
path: NodePath<any>,
helpers: {
wrapAsync: any;
wrapAwait?: any;
wrapAsync: t.Expression;
wrapAwait?: t.Expression;
},
noNewArrows?: boolean,
ignoreFunctionLength?: boolean,
Expand Down
2 changes: 1 addition & 1 deletion packages/babel-helper-simple-access/src/index.ts
Expand Up @@ -20,7 +20,7 @@ type State = {
};
export default function simplifyAccess(
path: NodePath,
bindingNames,
bindingNames: Set<string>,
// TODO(Babel 8): Remove this
includeUpdateExpression: boolean = true,
) {
Expand Down