* Extract a class property declaration (e.g. C# `public string Name { get; set; }`). * Extracts as 'property' kind node inside the owning class.
(node: SyntaxNode)
| 1857 | * Extracts as 'property' kind node inside the owning class. |
| 1858 | */ |
| 1859 | private extractProperty(node: SyntaxNode): Node | null { |
| 1860 | if (!this.extractor) return null; |
| 1861 | |
| 1862 | const docstring = getPrecedingDocstring(node, this.source); |
| 1863 | const visibility = this.extractor.getVisibility?.(node); |
| 1864 | const isStatic = this.extractor.isStatic?.(node) ?? false; |
| 1865 | |
| 1866 | const hookName = this.extractor.extractPropertyName?.(node, this.source); |
| 1867 | // JS `field_definition` names its key the `property` field (TS uses |
| 1868 | // `name`) — try both before the generic identifier scan (#808). |
| 1869 | const nameNode = hookName |
| 1870 | ? null |
| 1871 | : getChildByField(node, 'name') || |
| 1872 | getChildByField(node, 'property') || |
| 1873 | node.namedChildren.find(c => c.type === 'identifier'); |
| 1874 | const name = hookName ?? (nameNode ? getNodeText(nameNode, this.source) : null); |
| 1875 | if (!name) return null; |
| 1876 | |
| 1877 | // Get property type. TS/JS field definitions carry an explicit `type` |
| 1878 | // field (a `type_annotation`); their other named children are the name |
| 1879 | // and the initializer VALUE, which the generic finder below would |
| 1880 | // wrongly pick — so fields use the type field only (#808). Other |
| 1881 | // languages (C# property_declaration) keep the generic scan. |
| 1882 | const isTsJsField = |
| 1883 | node.type === 'public_field_definition' || node.type === 'field_definition'; |
| 1884 | const typeNode = isTsJsField |
| 1885 | ? getChildByField(node, 'type') |
| 1886 | : node.namedChildren.find( |
| 1887 | c => c.type !== 'modifier' && c.type !== 'modifiers' |
| 1888 | && c.type !== 'identifier' && c.type !== 'accessor_list' |
| 1889 | && c.type !== 'accessors' && c.type !== 'equals_value_clause' |
| 1890 | ); |
| 1891 | const typeText = typeNode |
| 1892 | ? getNodeText(typeNode, this.source).replace(/^:\s*/, '') |
| 1893 | : undefined; |
| 1894 | const signature = typeText ? `${typeText} ${name}` : name; |
| 1895 | |
| 1896 | const propNode = this.createNode('property', name, node, { |
| 1897 | docstring, |
| 1898 | signature, |
| 1899 | visibility, |
| 1900 | isStatic, |
| 1901 | }); |
| 1902 | |
| 1903 | // `@Inject() private svc: Foo` and similar — capture the |
| 1904 | // decorator->target relationship for class properties too. |
| 1905 | if (propNode) { |
| 1906 | this.extractDecoratorsFor(node, propNode.id); |
| 1907 | // Emit `references` edges from the property to types named in its |
| 1908 | // type annotation (#381). The generic walker handles TS-style |
| 1909 | // `type_annotation` children; the C# branch walks the `type` field. |
| 1910 | this.extractTypeAnnotations(node, propNode.id); |
| 1911 | } |
| 1912 | return propNode; |
| 1913 | } |
| 1914 | |
| 1915 | /** |
| 1916 | * Extract a class field declaration (e.g. Java field_declaration, C# field_declaration). |
no test coverage detected