Skip to content

Commit

Permalink
Improve @babel/helper-* typings (#14620)
Browse files Browse the repository at this point in the history
* improve helper-function-name typings

* helper hoist variables

* helper-member-expression-to-functions

* helper-simple-access

* remap-async-to-generator

* helper-annotate-as-pure

* helper-builder-binary-assignment-operator-visitor

* helper-check-duplicate-nodes

* early return when export declaration is export all

* split-export-declaration

* helper-define-map

* define-map

* Update packages/babel-helper-builder-binary-assignment-operator-visitor/src/index.ts

Co-authored-by: Nicol貌 Ribaudo <nicolo.ribaudo@gmail.com>

* review comments

Co-authored-by: Nicol貌 Ribaudo <nicolo.ribaudo@gmail.com>
  • Loading branch information
JLHwung and nicolo-ribaudo committed Jun 21, 2022
1 parent 88378e2 commit 2ea5c45
Show file tree
Hide file tree
Showing 12 changed files with 149 additions and 65 deletions.
12 changes: 6 additions & 6 deletions packages/babel-helper-annotate-as-pure/src/index.ts
@@ -1,16 +1,16 @@
import { addComment } from "@babel/types";
import type { Node } from "@babel/types";
import { addComment, type Node } from "@babel/types";
import type { NodePath } from "@babel/traverse";

const PURE_ANNOTATION = "#__PURE__";

const isPureAnnotated = ({ leadingComments }: Node): boolean =>
!!leadingComments &&
leadingComments.some(comment => /[@#]__PURE__/.test(comment.value));

export default function annotateAsPure(
pathOrNode: Node | { node: Node },
): void {
const node = pathOrNode["node"] || pathOrNode;
export default function annotateAsPure(pathOrNode: Node | NodePath): void {
const node =
// @ts-expect-error Node will not have `node` property
(pathOrNode["node"] || pathOrNode) as Node;
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 type * as t from "@babel/types";

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

0 comments on commit 2ea5c45

Please sign in to comment.