* Walk the AST to find all function-like nodes (in document order). * For each, extract propsName and collect JSX elements from its body.
( node: Node, annotated: Set<number>, file: string, ignorePatterns: Array<string | RegExp>, offsetToLoc: (offset: number) => Loc, s: MagicString, code: string, )
| 116 | * For each, extract propsName and collect JSX elements from its body. |
| 117 | */ |
| 118 | function visitFunctions( |
| 119 | node: Node, |
| 120 | annotated: Set<number>, |
| 121 | file: string, |
| 122 | ignorePatterns: Array<string | RegExp>, |
| 123 | offsetToLoc: (offset: number) => Loc, |
| 124 | s: MagicString, |
| 125 | code: string, |
| 126 | ): boolean { |
| 127 | let didTransform = false |
| 128 | |
| 129 | const processFunction = (params: Array<ParamPattern>, body: Node) => { |
| 130 | const propsName = getPropsName(params) |
| 131 | const jsxNodes: Array<JSXOpeningElement> = [] |
| 132 | collectJsx(body, jsxNodes) |
| 133 | |
| 134 | for (const jsx of jsxNodes) { |
| 135 | if (annotated.has(jsx.start)) continue |
| 136 | if (!shouldTransform(jsx, propsName, ignorePatterns)) continue |
| 137 | |
| 138 | const loc = offsetToLoc(jsx.start) |
| 139 | const attrStr = ` data-tsd-source="${file}:${loc.line}:${loc.column + 1}"` |
| 140 | |
| 141 | // Insert before '>' or '/>' at the end of the opening element |
| 142 | if (jsx.selfClosing) { |
| 143 | // ends with '/>' — insert before '/>' |
| 144 | s.appendLeft(jsx.end - 2, attrStr) |
| 145 | } else { |
| 146 | // ends with '>' — insert before '>' |
| 147 | s.appendLeft(jsx.end - 1, attrStr) |
| 148 | } |
| 149 | |
| 150 | annotated.add(jsx.start) |
| 151 | didTransform = true |
| 152 | } |
| 153 | } |
| 154 | |
| 155 | // Check if this node is a function-like node. Variable-initialized |
| 156 | // functions (`const Foo = () => {}`) are handled when forEachChild reaches |
| 157 | // their init, so VariableDeclaration doesn't need a special case here. |
| 158 | if ( |
| 159 | node.type === 'FunctionDeclaration' || |
| 160 | node.type === 'FunctionExpression' |
| 161 | ) { |
| 162 | if (node.body) processFunction(node.params, node.body) |
| 163 | } else if (node.type === 'ArrowFunctionExpression') { |
| 164 | processFunction(node.params, node.body) |
| 165 | } |
| 166 | |
| 167 | // Recurse into children to find nested functions |
| 168 | forEachChild(node, (child) => { |
| 169 | if ( |
| 170 | visitFunctions( |
| 171 | child, |
| 172 | annotated, |
| 173 | file, |
| 174 | ignorePatterns, |
| 175 | offsetToLoc, |
no test coverage detected