* Extract a function
(node: SyntaxNode, nameOverride?: string)
| 1388 | * Extract a function |
| 1389 | */ |
| 1390 | private extractFunction(node: SyntaxNode, nameOverride?: string): void { |
| 1391 | if (!this.extractor) return; |
| 1392 | |
| 1393 | // If the language provides getReceiverType and this function has a receiver |
| 1394 | // (e.g., Rust function_item inside an impl block), extract as method instead |
| 1395 | if (this.extractor.getReceiverType?.(node, this.source)) { |
| 1396 | this.extractMethod(node); |
| 1397 | return; |
| 1398 | } |
| 1399 | |
| 1400 | // nameOverride is supplied only for explicitly-named anonymous functions the |
| 1401 | // caller resolved itself (e.g. arrow values of exported-const object members |
| 1402 | // — SvelteKit actions). Inline-object arrows reached by the general walker |
| 1403 | // get no override, so they still fall through to the <anonymous> skip below. |
| 1404 | let name = nameOverride ?? extractName(node, this.source, this.extractor); |
| 1405 | // For arrow functions and function expressions assigned to variables, |
| 1406 | // resolve the name from the parent variable_declarator. |
| 1407 | // e.g. `export const useAuth = () => { ... }` — the arrow_function node |
| 1408 | // has no `name` field; the name lives on the variable_declarator. |
| 1409 | if ( |
| 1410 | !nameOverride && |
| 1411 | name === '<anonymous>' && |
| 1412 | (node.type === 'arrow_function' || node.type === 'function_expression') |
| 1413 | ) { |
| 1414 | const parent = node.parent; |
| 1415 | if (parent?.type === 'variable_declarator') { |
| 1416 | const varName = getChildByField(parent, 'name'); |
| 1417 | if (varName) { |
| 1418 | name = getNodeText(varName, this.source); |
| 1419 | } |
| 1420 | } |
| 1421 | } |
| 1422 | if (name === '<anonymous>') { |
| 1423 | // Don't emit a node for the anonymous wrapper itself, but still visit its |
| 1424 | // body: AMD/RequireJS and CommonJS module wrappers (`define([], function(){…})`, |
| 1425 | // `(function(){…})()`) hold named inner functions and calls that would |
| 1426 | // otherwise be lost — the dispatcher set skipChildren, so nothing else |
| 1427 | // descends into this subtree. (#528) |
| 1428 | const body = this.extractor.resolveBody?.(node, this.extractor.bodyField) |
| 1429 | ?? getChildByField(node, this.extractor.bodyField); |
| 1430 | if (body) { |
| 1431 | this.visitFunctionBody(body, ''); |
| 1432 | } |
| 1433 | return; |
| 1434 | } |
| 1435 | |
| 1436 | // Check for misparse artifacts (e.g. C++ macros causing "namespace detail" functions) |
| 1437 | // Skip the node but still visit the body for calls and structural nodes |
| 1438 | if (this.extractor.isMisparsedFunction?.(name, node)) { |
| 1439 | const body = this.extractor.resolveBody?.(node, this.extractor.bodyField) |
| 1440 | ?? getChildByField(node, this.extractor.bodyField); |
| 1441 | if (body) { |
| 1442 | this.visitFunctionBody(body, ''); |
| 1443 | } |
| 1444 | return; |
| 1445 | } |
| 1446 | |
| 1447 | const docstring = getPrecedingDocstring(node, this.source); |
no test coverage detected