feat: Add resolveBody hook for JS/TS class field function extraction
Addresses arrow function class fields like `field = () => { ... }` where the function body is nested inside field_definition nodes. Adds resolveBody method to traverse field_definition → arrow_function/function_expression → body and handles HOF wrapper patterns like `field = throttle(() => { ... })` by searching call_expression arguments. Enables proper function body extraction for class field functions in both JavaScript and TypeScript.
This commit is contained in:
@@ -14,6 +14,34 @@ export const javascriptExtractor: LanguageExtractor = {
|
|||||||
variableTypes: ['lexical_declaration', 'variable_declaration'],
|
variableTypes: ['lexical_declaration', 'variable_declaration'],
|
||||||
nameField: 'name',
|
nameField: 'name',
|
||||||
bodyField: 'body',
|
bodyField: 'body',
|
||||||
|
resolveBody: (node, bodyField) => {
|
||||||
|
// field_definition (arrow function class fields) nest the body inside
|
||||||
|
// an arrow_function or function_expression child:
|
||||||
|
// field_definition → arrow_function → body (statement_block)
|
||||||
|
// Also handles wrapper patterns like: field = throttle((e) => { ... })
|
||||||
|
// field_definition → call_expression → arguments → arrow_function → body
|
||||||
|
if (node.type === 'field_definition') {
|
||||||
|
for (let i = 0; i < node.namedChildCount; i++) {
|
||||||
|
const child = node.namedChild(i);
|
||||||
|
if (!child) continue;
|
||||||
|
if (child.type === 'arrow_function' || child.type === 'function_expression') {
|
||||||
|
return getChildByField(child, bodyField);
|
||||||
|
}
|
||||||
|
if (child.type === 'call_expression') {
|
||||||
|
const args = getChildByField(child, 'arguments');
|
||||||
|
if (args) {
|
||||||
|
for (let j = 0; j < args.namedChildCount; j++) {
|
||||||
|
const arg = args.namedChild(j);
|
||||||
|
if (arg && (arg.type === 'arrow_function' || arg.type === 'function_expression')) {
|
||||||
|
return getChildByField(arg, bodyField);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
paramsField: 'parameters',
|
paramsField: 'parameters',
|
||||||
getSignature: (node, source) => {
|
getSignature: (node, source) => {
|
||||||
const params = getChildByField(node, 'parameters');
|
const params = getChildByField(node, 'parameters');
|
||||||
|
|||||||
@@ -15,6 +15,35 @@ export const typescriptExtractor: LanguageExtractor = {
|
|||||||
variableTypes: ['lexical_declaration', 'variable_declaration'],
|
variableTypes: ['lexical_declaration', 'variable_declaration'],
|
||||||
nameField: 'name',
|
nameField: 'name',
|
||||||
bodyField: 'body',
|
bodyField: 'body',
|
||||||
|
resolveBody: (node, bodyField) => {
|
||||||
|
// public_field_definition (arrow function class fields) nest the body inside
|
||||||
|
// an arrow_function or function_expression child:
|
||||||
|
// public_field_definition → arrow_function → body (statement_block)
|
||||||
|
// Also handles wrapper patterns like: field = withBatchedUpdates((e) => { ... })
|
||||||
|
// public_field_definition → call_expression → arguments → arrow_function → body
|
||||||
|
if (node.type === 'public_field_definition') {
|
||||||
|
for (let i = 0; i < node.namedChildCount; i++) {
|
||||||
|
const child = node.namedChild(i);
|
||||||
|
if (!child) continue;
|
||||||
|
if (child.type === 'arrow_function' || child.type === 'function_expression') {
|
||||||
|
return getChildByField(child, bodyField);
|
||||||
|
}
|
||||||
|
// Check inside call_expression arguments (HOF wrappers like throttle, debounce)
|
||||||
|
if (child.type === 'call_expression') {
|
||||||
|
const args = getChildByField(child, 'arguments');
|
||||||
|
if (args) {
|
||||||
|
for (let j = 0; j < args.namedChildCount; j++) {
|
||||||
|
const arg = args.namedChild(j);
|
||||||
|
if (arg && (arg.type === 'arrow_function' || arg.type === 'function_expression')) {
|
||||||
|
return getChildByField(arg, bodyField);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
paramsField: 'parameters',
|
paramsField: 'parameters',
|
||||||
returnField: 'return_type',
|
returnField: 'return_type',
|
||||||
getSignature: (node, source) => {
|
getSignature: (node, source) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user