* Extract a class property declaration (e.g. C# `public string Name { get; set; }`). * Extracts as 'property' kind node inside the owning class.
(node: SyntaxNode)
| 1984 | * Extracts as 'property' kind node inside the owning class. |
| 1985 | */ |
| 1986 | private extractProperty(node: SyntaxNode): Node | null { |
| 1987 | if (!this.extractor) return null; |
| 1988 | |
| 1989 | const docstring = getPrecedingDocstring(node, this.source); |
| 1990 | const visibility = this.extractor.getVisibility?.(node); |
| 1991 | const isStatic = this.extractor.isStatic?.(node) ?? false; |
| 1992 | |
| 1993 | const hookName = this.extractor.extractPropertyName?.(node, this.source); |
| 1994 | // JS `field_definition` names its key the `property` field (TS uses |
| 1995 | // `name`) — try both before the generic identifier scan (#808). |
| 1996 | const nameNode = hookName |
| 1997 | ? null |
| 1998 | : getChildByField(node, 'name') || |
| 1999 | getChildByField(node, 'property') || |
| 2000 | node.namedChildren.find(c => c.type === 'identifier'); |
| 2001 | const name = hookName ?? (nameNode ? getNodeText(nameNode, this.source) : null); |
| 2002 | if (!name) return null; |
| 2003 | |
| 2004 | // Get property type. TS/JS field definitions carry an explicit `type` |
| 2005 | // field (a `type_annotation`); their other named children are the name |
| 2006 | // and the initializer VALUE, which the generic finder below would |
| 2007 | // wrongly pick — so fields use the type field only (#808). Other |
| 2008 | // languages (C# property_declaration) keep the generic scan. |
| 2009 | const isTsJsField = |
| 2010 | node.type === 'public_field_definition' || node.type === 'field_definition'; |
| 2011 | const typeNode = isTsJsField |
| 2012 | ? getChildByField(node, 'type') |
| 2013 | : node.namedChildren.find( |
| 2014 | c => c.type !== 'modifier' && c.type !== 'modifiers' |
| 2015 | && c.type !== 'identifier' && c.type !== 'accessor_list' |
| 2016 | && c.type !== 'accessors' && c.type !== 'equals_value_clause' |
| 2017 | ); |
| 2018 | const typeText = typeNode |
| 2019 | ? getNodeText(typeNode, this.source).replace(/^:\s*/, '') |
| 2020 | : undefined; |
| 2021 | const signature = typeText ? `${typeText} ${name}` : name; |
| 2022 | |
| 2023 | const propNode = this.createNode('property', name, node, { |
| 2024 | docstring, |
| 2025 | signature, |
| 2026 | visibility, |
| 2027 | isStatic, |
| 2028 | }); |
| 2029 | |
| 2030 | // `@Inject() private svc: Foo` and similar — capture the |
| 2031 | // decorator->target relationship for class properties too. |
| 2032 | if (propNode) { |
| 2033 | this.extractDecoratorsFor(node, propNode.id); |
| 2034 | // Emit `references` edges from the property to types named in its |
| 2035 | // type annotation (#381). The generic walker handles TS-style |
| 2036 | // `type_annotation` children; the C# branch walks the `type` field. |
| 2037 | this.extractTypeAnnotations(node, propNode.id); |
| 2038 | } |
| 2039 | return propNode; |
| 2040 | } |
| 2041 | |
| 2042 | /** |
| 2043 | * Extract a class field declaration (e.g. Java field_declaration, C# field_declaration). |
no test coverage detected