Skip to content

Commit a7832ab

Browse files
committed
fix(extractor): guard handleFieldDef to only emit callable field definitions (#1399)
Impact: 2 functions changed, 18 affected
1 parent e2d9e4d commit a7832ab

3 files changed

Lines changed: 22 additions & 2 deletions

File tree

crates/codegraph-core/src/extractors/javascript.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -908,7 +908,12 @@ fn handle_field_def(node: &Node, source: &[u8], symbols: &mut FileSymbols) {
908908
return;
909909
}
910910
// Skip uninitialised fields (`class C { x; }`) — must have a value node.
911-
let Some(_value_node) = node.child_by_field_name("value") else { return };
911+
let Some(value_node) = node.child_by_field_name("value") else { return };
912+
// Only emit a callable definition when the initializer is a function/arrow expression.
913+
// Scalar fields like `static x = 42` should not appear as method-kind nodes.
914+
if !matches!(value_node.kind(), "arrow_function" | "function_expression" | "generator_function") {
915+
return;
916+
}
912917
let field_name = node_text(&name_node, source);
913918
if field_name.is_empty() { return; }
914919
let Some(class_name) = find_parent_class(node, source) else { return };

src/extractors/javascript.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -876,6 +876,12 @@ function handleStaticBlock(node: TreeSitterNode, definitions: Definition[]): voi
876876
* `public_field_definition` uses `'name'`. As a third fallback (Rust/TS parity) we
877877
* also check for a positional `property_identifier` child.
878878
*/
879+
const CALLABLE_FIELD_TYPES = new Set([
880+
'arrow_function',
881+
'function_expression',
882+
'generator_function',
883+
]);
884+
879885
function handleFieldDef(node: TreeSitterNode, definitions: Definition[]): void {
880886
// JS field_definition uses 'property' field; TS public_field_definition uses 'name' field
881887
const nameNode =
@@ -885,6 +891,9 @@ function handleFieldDef(node: TreeSitterNode, definitions: Definition[]): void {
885891
const valueNode = node.childForFieldName('value');
886892
if (!nameNode || !valueNode) return;
887893
if (nameNode.type === 'computed_property_name') return;
894+
// Only emit a callable definition when the initializer is a function/arrow expression.
895+
// Scalar fields like `static x = 42` should not appear as method-kind nodes.
896+
if (!CALLABLE_FIELD_TYPES.has(valueNode.type)) return;
888897
const fieldName = nameNode.text;
889898
if (!fieldName) return;
890899
const parentClass = findParentClass(node);

tests/parsers/javascript.test.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,18 @@ describe('JavaScript parser', () => {
9999
});
100100

101101
it('extracts static class field definitions as method definitions', () => {
102-
const symbols = parseJS(`class C6 { static staticProperty = (f1(), function() {}); }`);
102+
const symbols = parseJS(`class C6 { static staticProperty = function() {}; }`);
103103
expect(symbols.definitions).toContainEqual(
104104
expect.objectContaining({ name: 'C6.staticProperty', kind: 'method' }),
105105
);
106106
});
107107

108+
it('does not extract scalar static field definitions as method definitions', () => {
109+
const symbols = parseJS(`class C7 { static x = 42; }`);
110+
const names = symbols.definitions.map((d: { name: string }) => d.name);
111+
expect(names).not.toContain('C7.x');
112+
});
113+
108114
it('extracts static blocks as method definitions with unique names', () => {
109115
const symbols = parseJS(`class C6 { static { f1(); } static { f2(); } }`);
110116
// Each static block gets a unique name with line:column suffix to avoid collisions

0 commit comments

Comments
 (0)