* Extract a function
(node: SyntaxNode, nameOverride?: string)
| 1521 | * Extract a function |
| 1522 | */ |
| 1523 | private extractFunction(node: SyntaxNode, nameOverride?: string): void { |
| 1524 | if (!this.extractor) return; |
| 1525 | |
| 1526 | // If the language provides getReceiverType and this function has a receiver |
| 1527 | // (e.g., Rust function_item inside an impl block), extract as method instead |
| 1528 | if (this.extractor.getReceiverType?.(node, this.source)) { |
| 1529 | this.extractMethod(node); |
| 1530 | return; |
| 1531 | } |
| 1532 | |
| 1533 | // nameOverride is supplied only for explicitly-named anonymous functions the |
| 1534 | // caller resolved itself (e.g. arrow values of exported-const object members |
| 1535 | // — SvelteKit actions). Inline-object arrows reached by the general walker |
| 1536 | // get no override, so they still fall through to the <anonymous> skip below. |
| 1537 | let name = nameOverride ?? extractName(node, this.source, this.extractor); |
| 1538 | // For arrow functions and function expressions assigned to variables, |
| 1539 | // resolve the name from the parent variable_declarator. |
| 1540 | // e.g. `export const useAuth = () => { ... }` — the arrow_function node |
| 1541 | // has no `name` field; the name lives on the variable_declarator. |
| 1542 | if ( |
| 1543 | !nameOverride && |
| 1544 | name === '<anonymous>' && |
| 1545 | (node.type === 'arrow_function' || node.type === 'function_expression') |
| 1546 | ) { |
| 1547 | const parent = node.parent; |
| 1548 | if (parent?.type === 'variable_declarator') { |
| 1549 | const varName = getChildByField(parent, 'name'); |
| 1550 | if (varName) { |
| 1551 | name = getNodeText(varName, this.source); |
| 1552 | } |
| 1553 | } |
| 1554 | } |
| 1555 | if (name === '<anonymous>') { |
| 1556 | // Don't emit a node for the anonymous wrapper itself, but still visit its |
| 1557 | // body: AMD/RequireJS and CommonJS module wrappers (`define([], function(){…})`, |
| 1558 | // `(function(){…})()`) hold named inner functions and calls that would |
| 1559 | // otherwise be lost — the dispatcher set skipChildren, so nothing else |
| 1560 | // descends into this subtree. (#528) |
| 1561 | const body = this.extractor.resolveBody?.(node, this.extractor.bodyField) |
| 1562 | ?? getChildByField(node, this.extractor.bodyField); |
| 1563 | if (body) { |
| 1564 | this.visitFunctionBody(body, ''); |
| 1565 | } |
| 1566 | return; |
| 1567 | } |
| 1568 | |
| 1569 | // Check for misparse artifacts (e.g. C++ macros causing "namespace detail" functions) |
| 1570 | // Skip the node but still visit the body for calls and structural nodes |
| 1571 | if (this.extractor.isMisparsedFunction?.(name, node)) { |
| 1572 | const body = this.extractor.resolveBody?.(node, this.extractor.bodyField) |
| 1573 | ?? getChildByField(node, this.extractor.bodyField); |
| 1574 | if (body) { |
| 1575 | this.visitFunctionBody(body, ''); |
| 1576 | } |
| 1577 | return; |
| 1578 | } |
| 1579 | |
| 1580 | const docstring = getPrecedingDocstring(node, this.source); |
no test coverage detected