feat: enhance TypeScript/TSX tree-sitter parser

- Enhanced the Tree-Sitter parser for JavaScript/TypeScript with support for advanced language constructs
- Modified the parser to exclude comments from the output
- Consolidated sample code in tests for better maintainability

Signed-off-by: Eric Wheeler <roo-code@z.ewheeler.org>
This commit is contained in:
Eric Wheeler 2025-04-08 19:22:10 -07:00
parent 9f724bd360
commit 63358e794d
3 changed files with 304 additions and 3 deletions

View file

@ -7,8 +7,9 @@ import { loadRequiredLanguageParsers } from "../languageParser"
import tsxQuery from "../queries/tsx"
import { initializeTreeSitter, testParseSourceCodeDefinitions, inspectTreeStructure, debugLog } from "./helpers"
// Sample component content
// Sample component content with enhanced TypeScript language constructs
const sampleTsxContent = `
// Original components
interface VSCodeCheckboxProps {
checked: boolean
onChange: (checked: boolean) => void
@ -66,7 +67,236 @@ const TemperatureControl = ({
</>
)
}
}`
// Utility Types
type User = {
id: string;
username: string;
password: string;
email: string;
}
// Partial - Makes all properties optional
type PartialUser = Partial<User>;
// Required - Makes all properties required
type RequiredConfig = Required<{theme?: string, showHeader?: boolean}>;
// Readonly - Makes all properties readonly
type ReadonlyState = Readonly<{count: number, status: string}>;
// Function Overloads
function process(value: string): string;
function process(value: number): number;
function process(value: boolean): boolean;
function process(value: any): any {
return value;
}
// Async Function
async function fetchData(url: string): Promise<Response> {
const response = await fetch(url);
return response;
}
// Async Arrow Function
const fetchUser = async (id: string): Promise<User> => {
const response = await fetch(\`/api/users/\${id}\`);
return response.json();
};
// Class with Members and Properties
class AdvancedComponent {
// Public property
public name: string;
// Private property
private _count: number = 0;
// Protected property
protected status: 'active' | 'inactive' = 'active';
// Readonly property
readonly id: string;
// Static property
static defaultProps = {
theme: 'light',
showHeader: true
};
// Constructor
constructor(name: string, id: string) {
this.name = name;
this.id = id;
}
// Getter method
get count(): number {
return this._count;
}
// Setter method
set count(value: number) {
if (value >= 0) {
this._count = value;
}
}
// Public method
public updateName(newName: string): void {
this.name = newName;
}
}
// React Hooks and Context
import React, { createContext, useContext, useState, useEffect } from 'react';
// Create a context
const ThemeContext = createContext({
theme: 'light',
toggleTheme: () => {}
});
// Context provider and consumer
const ThemeProvider = ThemeContext.Provider;
const ThemeConsumer = ThemeContext.Consumer;
// Custom hook using context
function useTheme() {
const context = useContext(ThemeContext);
if (!context) {
throw new Error('useTheme must be used within a ThemeProvider');
}
return context;
}
// Component using hooks
function ThemeToggler() {
// useState hook
const [theme, setTheme] = useState('light');
// useEffect hook
useEffect(() => {
document.body.dataset.theme = theme;
return () => {
delete document.body.dataset.theme;
};
}, [theme]);
return (
<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
Switch to {theme === 'light' ? 'dark' : 'light'} theme
</button>
);
}
// Decorator Example
@Component({
selector: 'app-root',
template: '<div>App Component</div>'
})
class AppComponent {
title = 'My App';
@Input()
data: string[] = [];
}
// Enum Declaration
enum LogLevel {
Error = 1,
Warning = 2,
Info = 3,
Debug = 4
}
// Namespace Declaration
namespace Validation {
export function isValidEmail(email: string): boolean {
return email.includes('@');
}
export function isValidPhone(phone: string): boolean {
return phone.length >= 10;
}
}
// Complex Nested Components and Member Expressions
export const ComplexComponent = () => {
return (
<CustomHeader
title="Test"
subtitle={
<span className="text-gray-500">
Nested <strong>content</strong>
</span>
}
/>
);
};
export const NestedSelectors = () => (
<section>
<Select.Option>
<Group.Item>
<Text.Body>Deeply nested</Text.Body>
</Group.Item>
</Select.Option>
</section>
);
// Template Literal Types
type EventName<T extends string> = \`on\${Capitalize<T>}\`;
type CSSProperty<T extends string> = \`--\${T}\` | \`-webkit-\${T}\` | \`-moz-\${T}\` | \`-ms-\${T}\`;
type RouteParams<T extends string> = T extends \`\${string}:\${infer Param}/\${infer Rest}\`
? { [K in Param | keyof RouteParams<Rest>]: string }
: T extends \`\${string}:\${infer Param}\`
? { [K in Param]: string }
: {};
// Conditional Types
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
type Parameters<T> = T extends (...args: infer P) => any ? P : never;
type InstanceType<T> = T extends new (...args: any[]) => infer R ? R : never;
type IsFunction<T> = T extends (...args: any[]) => any ? true : false;
// Generic Components with Constraints
type ComplexProps<T> = {
data: T[];
render: (item: T) => React.ReactNode;
};
export const GenericList = <T extends { id: string }>({
data,
render
}: ComplexProps<T>) => (
<div>
{data.map(item => render(item))}
</div>
);
export const ConditionalComponent = ({ condition }) =>
condition ? (
<PrimaryContent>
<h1>Main Content</h1>
</PrimaryContent>
) : (
<FallbackContent />
);
// Dictionary Interface with Constrained Key Types
interface Dictionary<K extends string | number, V> {
get(key: K): V | undefined;
set(key: K, value: V): void;
has(key: K): boolean;
}
type KeyValuePair<K extends string | number, V> = {
key: K;
value: V;
};
`
// We'll use the debug test to test the parser directly

View file

@ -4,7 +4,19 @@ import typescriptQuery from "./typescript"
* Tree-sitter Query for TSX Files:
* Combines TypeScript queries with TSX-specific React component queries
*
* This query captures various TypeScript and React component definitions in TSX files.
* This query captures various TypeScript and React component definitions in TSX files,
* as well as advanced TypeScript language constructs.
*
* SUPPORTED LANGUAGE CONSTRUCTS:
* - React Components (Function, Arrow, Class)
* - Higher Order Components
* - JSX Elements and Expressions
* - React Hooks
* - Context Providers/Consumers
* - React-specific Decorators
*
* Note: Generic TypeScript constructs like Utility Types, Async Functions,
* Class Members, Enums, and Namespaces are defined in typescript.ts
*
* TSX COMPONENT STRUCTURE:
*
@ -182,4 +194,31 @@ export default `${typescriptQuery}
alternative: (jsx_self_closing_element
name: (identifier) @component)) @definition.conditional_component
(#match? @component "^[A-Z]")
; Enhanced TypeScript Support - React-specific patterns only
; Method Definitions specific to React components
(method_definition
name: (property_identifier) @name.definition.method) @definition.method
; React Hooks
(variable_declaration
(variable_declarator
name: (array_pattern) @name.definition.hook
value: (call_expression
function: (identifier) @hook_name))) @definition.hook
(#match? @hook_name "^use[A-Z]")
; Custom Hooks
(function_declaration
name: (identifier) @name.definition.custom_hook) @definition.custom_hook
(#match? @name.definition.custom_hook "^use[A-Z]")
; Context Providers and Consumers
(variable_declaration
(variable_declarator
name: (identifier) @name.definition.context
value: (member_expression))) @definition.context
; React-specific decorators
(decorator) @definition.decorator
`

View file

@ -8,6 +8,11 @@
- switch/case statements with complex case blocks
- enum declarations with members
- namespace declarations
- utility types
- class members and properties
- constructor methods
- getter/setter methods
- async functions and arrow functions
*/
export default `
(function_signature
@ -88,4 +93,31 @@ export default `
(type_alias_declaration
name: (type_identifier) @name.definition.type
type_parameters: (type_parameters)?) @definition.type
; Utility Types
(type_alias_declaration
name: (type_identifier) @name.definition.utility_type) @definition.utility_type
; Class Members and Properties
(public_field_definition
name: (property_identifier) @name.definition.property) @definition.property
; Constructor
(method_definition
name: (property_identifier) @name.definition.constructor
(#eq? @name.definition.constructor "constructor")) @definition.constructor
; Getter/Setter Methods
(method_definition
name: (property_identifier) @name.definition.accessor) @definition.accessor
; Async Functions
(function_declaration
name: (identifier) @name.definition.async_function) @definition.async_function
; Async Arrow Functions
(variable_declaration
(variable_declarator
name: (identifier) @name.definition.async_arrow
value: (arrow_function))) @definition.async_arrow
`