From ac37bf73b9a666d109bc9c22a6500f24f91eb592 Mon Sep 17 00:00:00 2001 From: Diogo Doreto Date: Wed, 8 Oct 2025 15:00:05 +0200 Subject: [PATCH 1/3] fix(react-docgen): add ObjectMethod support to resolveName Extend the resolveName function in getMemberExpressionValuePath.ts to handle ObjectMethod nodes, preventing the error below from being thrown during AST resolution of member expressions within object methods. TypeError: Attempted to resolveName for an unsupported path. resolveName does not accept ObjectMethod. Fix https://github.com/reactjs/react-docgen/issues/902 --- .changeset/tired-ideas-invent.md | 5 ++++ .../utils/__tests__/resolveToValue-test.ts | 26 +++++++++++++++++++ .../src/utils/getMemberExpressionValuePath.ts | 1 + 3 files changed, 32 insertions(+) create mode 100644 .changeset/tired-ideas-invent.md diff --git a/.changeset/tired-ideas-invent.md b/.changeset/tired-ideas-invent.md new file mode 100644 index 00000000000..d7fc0ae2709 --- /dev/null +++ b/.changeset/tired-ideas-invent.md @@ -0,0 +1,5 @@ +--- +'react-docgen': patch +--- + +Do not fail when resolving inside ObjectMethod nodes diff --git a/packages/react-docgen/src/utils/__tests__/resolveToValue-test.ts b/packages/react-docgen/src/utils/__tests__/resolveToValue-test.ts index 1a00dde6fd6..ad09b40a891 100644 --- a/packages/react-docgen/src/utils/__tests__/resolveToValue-test.ts +++ b/packages/react-docgen/src/utils/__tests__/resolveToValue-test.ts @@ -269,4 +269,30 @@ describe('resolveToValue', () => { expect(resolveToValue(path)).toBe(path); }); }); + + describe('ObjectMethod', () => { + test('does not throw', () => { + const def = parse.statement( + `const slice = createSlice({ + example(state, action) { + state.images[action.payload.id] = action.payload.content; + }, + });`, + ); + + // path to `action.payload.id` + const path = def + .get('declarations')[0] + .get('init') + .get('arguments')[0] + .get('properties')[0] + .get('body') + .get('body')[0] + .get('expression') + .get('left') + .get('property'); + + expect(() => resolveToValue(path)).not.toThrow(); + }); + }); }); diff --git a/packages/react-docgen/src/utils/getMemberExpressionValuePath.ts b/packages/react-docgen/src/utils/getMemberExpressionValuePath.ts index c2a73e681d2..3d0f0400fcf 100644 --- a/packages/react-docgen/src/utils/getMemberExpressionValuePath.ts +++ b/packages/react-docgen/src/utils/getMemberExpressionValuePath.ts @@ -42,6 +42,7 @@ function resolveName(path: NodePath): string | undefined { path.isArrowFunctionExpression() || path.isTaggedTemplateExpression() || path.isCallExpression() || + path.isObjectMethod() || isReactForwardRefCall(path) ) { let currentPath: NodePath = path; From dc3acdfda37bc0d0f9451b966a6b6d75a8f02db2 Mon Sep 17 00:00:00 2001 From: Diogo Doreto Date: Wed, 8 Oct 2025 16:39:58 +0200 Subject: [PATCH 2/3] refactor: extract ObjectMethod handling to a dedicated condition --- .../src/utils/getMemberExpressionValuePath.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/react-docgen/src/utils/getMemberExpressionValuePath.ts b/packages/react-docgen/src/utils/getMemberExpressionValuePath.ts index 3d0f0400fcf..c1e63b62a69 100644 --- a/packages/react-docgen/src/utils/getMemberExpressionValuePath.ts +++ b/packages/react-docgen/src/utils/getMemberExpressionValuePath.ts @@ -42,7 +42,6 @@ function resolveName(path: NodePath): string | undefined { path.isArrowFunctionExpression() || path.isTaggedTemplateExpression() || path.isCallExpression() || - path.isObjectMethod() || isReactForwardRefCall(path) ) { let currentPath: NodePath = path; @@ -64,6 +63,16 @@ function resolveName(path: NodePath): string | undefined { return; } + if (path.isObjectMethod()) { + const key = path.get('key'); + + if (key.isIdentifier()) { + return key.node.name; + } + + return; + } + throw new TypeError( 'Attempted to resolveName for an unsupported path. resolveName does not accept ' + path.node.type + From d27b6bc0aba16f9dc4859097c17888f1e197a32a Mon Sep 17 00:00:00 2001 From: Daniel Tschinder <231804+danez@users.noreply.github.com> Date: Wed, 8 Oct 2025 21:01:05 +0000 Subject: [PATCH 3/3] ignore ObjectMethod --- .../getMemberExpressionValuePath-test.ts | 21 +++++++++++++++++++ .../src/utils/getMemberExpressionValuePath.ts | 16 ++++++-------- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/packages/react-docgen/src/utils/__tests__/getMemberExpressionValuePath-test.ts b/packages/react-docgen/src/utils/__tests__/getMemberExpressionValuePath-test.ts index 2f4824ad175..69084c39d00 100644 --- a/packages/react-docgen/src/utils/__tests__/getMemberExpressionValuePath-test.ts +++ b/packages/react-docgen/src/utils/__tests__/getMemberExpressionValuePath-test.ts @@ -1,6 +1,8 @@ +import type { ObjectMethod, VariableDeclaration } from '@babel/types'; import { parse } from '../../../tests/utils'; import getMemberExpressionValuePath from '../getMemberExpressionValuePath.js'; import { describe, expect, test } from 'vitest'; +import type { NodePath } from '@babel/traverse'; describe('getMemberExpressionValuePath', () => { describe('MethodExpression', () => { @@ -101,4 +103,23 @@ describe('getMemberExpressionValuePath', () => { ); }); }); + describe('ObjectMethod', () => { + test('ignores ObjectMethod', () => { + const def = parse.statement(` + const slice = createSlice({ + example(state, action) { + }, + }); + `); + + // path to `action.payload.id` + const path = def + .get('declarations')[0] + .get('init') + .get('arguments')[0] + .get('properties')[0] as NodePath; + + expect(getMemberExpressionValuePath(path, 'images')).toBe(null); + }); + }); }); diff --git a/packages/react-docgen/src/utils/getMemberExpressionValuePath.ts b/packages/react-docgen/src/utils/getMemberExpressionValuePath.ts index c1e63b62a69..c418f7060c4 100644 --- a/packages/react-docgen/src/utils/getMemberExpressionValuePath.ts +++ b/packages/react-docgen/src/utils/getMemberExpressionValuePath.ts @@ -37,6 +37,12 @@ function resolveName(path: NodePath): string | undefined { return; } + // When we check ObjectMethod we simply ignore it as assigning + // to it is technicaly possible but rare + if (path.isObjectMethod()) { + return; + } + if ( path.isFunctionExpression() || path.isArrowFunctionExpression() || @@ -63,16 +69,6 @@ function resolveName(path: NodePath): string | undefined { return; } - if (path.isObjectMethod()) { - const key = path.get('key'); - - if (key.isIdentifier()) { - return key.node.name; - } - - return; - } - throw new TypeError( 'Attempted to resolveName for an unsupported path. resolveName does not accept ' + path.node.type +