Skip to content

Conversation

@JLHwung
Copy link
Contributor

@JLHwung JLHwung commented Sep 5, 2025

Q                       A
Fixed Issues? (NodePath("<div.A>").get(path to div).isReferencedIdentifier({ name: "div" }) returns false while NodePath("<div.A>").get(path to div).isReferencedIdentifier() returns true.
Patch: Bug Fix? Yes
Major: Breaking Change?
Minor: New Feature?
Tests Added + Pass? Yes
Documentation PR Link
Any Dependency Changes?
License MIT

In this PR we improved the is* and assert* helper typings: The assertion type is now narrowed by the provided options key, given that the options key is a partial AST match. We also excluded the type property in the options key since it makes no sense to provide type in the isHelper: e.g. t.isFor(node, { type: "ForStatement" }) should have been t.isForStatement(node).

The improved typings yields better helper usage in the codebase and we can remove a few @ts-expect-error.

Also fixed a isReferencedIdentifier implementation bug where we passed opts to the parent AST helper. Previously it will yield very confusing behaviour as mentioned above and I think it should be fixed in a patch release.

@JLHwung JLHwung added the PR: Bug Fix 🐛 A type of pull request used for our changelog categories label Sep 5, 2025
@babel-bot
Copy link
Collaborator

babel-bot commented Sep 5, 2025

Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/59905

if (path.parentPath.isUpdateExpression()) continue;
// It will be handled after transforming the loop
if (path.parentPath.isFor({ left: path.node })) continue;
if (path.parentPath.isForXStatement({ left: path.node })) continue;
Copy link
Contributor Author

@JLHwung JLHwung Sep 5, 2025

Choose a reason for hiding this comment

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

This is caught by the new typing because left does not present in ForStatement node. Here we can narrow isFor to isForXStatement.

this: NodePath,
opts?: Opts<VirtualTypeAliases["Flow"]>,
): this is NodePath<t.Flow>;
isExpression(this: NodePath): this is NodePath<t.Expression>;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The opts parameter is removed to align with the implementation.

}

// check if node is referenced
return nodeIsReferenced(node, parent, this.parentPath.parent);
Copy link
Contributor Author

@JLHwung JLHwung Sep 5, 2025

Choose a reason for hiding this comment

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

Previously this branch also handles the JSXIdentifier-in-JSXMemberExpression case, however at this point the opts are no longer checked against the JSXIdentifier node, so NodePath(<A.B/>).get(path to A).isReferencedIdentifier({ name: "NotA" }) would incorrectly return true. This is also fixed in the new implementation.

Copy link
Member

Choose a reason for hiding this comment

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

Could you update the PR title so that it properly describes this in the changelog?

@pkg-pr-new
Copy link

pkg-pr-new bot commented Sep 5, 2025

Open in StackBlitz

commit: 1054865

@JLHwung JLHwung requested a review from liuxingbaoyu September 5, 2025 16:33
@JLHwung JLHwung changed the title Improve is* and assert* helpers typing Fix JSXIdentifier handling in isReferencedIdentifier Sep 5, 2025
opts?: Options<VirtualTypeAliases["ReferencedIdentifier"]>,
): boolean {
const { node, parent } = this;
if (!isIdentifier(node, opts) && !isJSXMemberExpression(parent, opts)) {
Copy link
Contributor Author

@JLHwung JLHwung Sep 5, 2025

Choose a reason for hiding this comment

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

Previously we passed opts to isJSXMemberExpression, which will always return false when opts is e.g. { name: "foo" } because the JSXMemberExpression does not have a name property. This is fixed in the new implementation.


for (const type of [...t.TYPES].sort()) {
output += `is${type}(this: NodePath, opts?: Opts<t.${type}>): this is NodePath<t.${type}>;`;
output += `is${type}(this: NodePath): this is NodePath<t.${type}>;`;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here we provided an overload signature, because otherwise TS will throw

TS2684: The 'this' context of type 'NodePath | NodePath | NodePath | NodePath<...> | NodePath<...> | NodePath<...>' is not assignable to method's 'this' of type 'NodePath'.
Type 'NodePath' is not assignable to type 'NodePath'.
Property 'expression' is missing in type 'ClassMethod' but required in type 'ArrowFunctionExpression'.

in line 1114

if (
!init &&
!unique &&
(kind === "var" || kind === "let") &&
path.isFunction() &&
// @ts-expect-error ArrowFunctionExpression never has a name
!path.node.name &&
isCallExpression(path.parent, { callee: path.node }) &&
path.parent.arguments.length <= path.node.params.length &&
isIdentifier(id)
) {
path.pushContainer("params", id);

I think we may have to do it for the t.is* helpers as well.

// Signature overload to avoid issues like https://github.com/babel/babel/pull/17503#discussion_r2325598609
`export function is${type}(node: t.Node | null | undefined): ${result};`,
`export function is${type}<Opts extends Options<t.${type}>>(node: t.Node | null | undefined, opts?: Opts | null): ${resultWithOpts};`,
`export function is${type}<Opts extends Options<t.${type}>>(node: t.Node | null | undefined, opts?: Opts | null): ${resultWithOpts} {
Copy link
Member

Choose a reason for hiding this comment

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

This last one can probably just return boolean now, since its type is not actually exposed externally but only used to check the return type.

@JLHwung JLHwung merged commit e626523 into babel:main Sep 5, 2025
76 checks passed
@JLHwung JLHwung deleted the improve-is-helper-typing branch September 5, 2025 22:52
@github-actions github-actions bot added the outdated A closed issue/PR that is archived due to age. Recommended to make a new issue label Dec 6, 2025
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Dec 6, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

outdated A closed issue/PR that is archived due to age. Recommended to make a new issue PR: Bug Fix 🐛 A type of pull request used for our changelog categories

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants