diff --git a/esbuild.js b/esbuild.js index c6a555f5a52..68cf8806386 100644 --- a/esbuild.js +++ b/esbuild.js @@ -38,35 +38,21 @@ const copyWasmFiles = { path.join(distDir, "tiktoken_bg.wasm"), ) - // tree-sitter WASM - fs.copyFileSync( - path.join(nodeModulesDir, "web-tree-sitter", "tree-sitter.wasm"), - path.join(distDir, "tree-sitter.wasm"), - ) + // Copy language-specific WASM files + const languageWasmDir = path.join(__dirname, "node_modules", "tree-sitter-wasms", "out") - // language-specific tree-sitter WASMs - const languageWasmDir = path.join(nodeModulesDir, "tree-sitter-wasms", "out") - const languages = [ - "typescript", - "tsx", - "python", - "rust", - "javascript", - "go", - "cpp", - "c", - "c_sharp", - "ruby", - "java", - "php", - "swift", - "kotlin", - ] - - languages.forEach((lang) => { - const filename = `tree-sitter-${lang}.wasm` - fs.copyFileSync(path.join(languageWasmDir, filename), path.join(distDir, filename)) - }) + // Dynamically read all WASM files from the directory instead of using a hardcoded list + if (fs.existsSync(languageWasmDir)) { + const wasmFiles = fs.readdirSync(languageWasmDir).filter((file) => file.endsWith(".wasm")) + + console.log(`Copying ${wasmFiles.length} tree-sitter WASM files to dist directory`) + + wasmFiles.forEach((filename) => { + fs.copyFileSync(path.join(languageWasmDir, filename), path.join(distDir, filename)) + }) + } else { + console.warn(`Tree-sitter WASM directory not found: ${languageWasmDir}`) + } }) }, } diff --git a/src/services/tree-sitter/__tests__/fixtures/sample-c-sharp.ts b/src/services/tree-sitter/__tests__/fixtures/sample-c-sharp.ts new file mode 100644 index 00000000000..f1174f6e4ce --- /dev/null +++ b/src/services/tree-sitter/__tests__/fixtures/sample-c-sharp.ts @@ -0,0 +1,390 @@ +export default String.raw` +// Using directives test - at least 4 lines long +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +// Attribute declaration test - at least 4 lines long +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] +public class TestAttributeDefinition : Attribute +{ + // Attribute properties + public string Category { get; } + public int Priority { get; } + + // Constructor + public TestAttributeDefinition(string category, int priority = 0) + { + Category = category; + Priority = priority; + } +} + +// Namespace declaration test +namespace TestNamespaceDefinition +{ + // Interface declaration test - at least 4 lines long + public interface ITestInterfaceDefinition + { + // Interface method declarations + void TestInterfaceMethod(string message); + string TestInterfaceFormatMethod(string message, TestEnumDefinition level); + int TestInterfaceCalculateMethod(int x, int y); + } + + // Enum declaration test - at least 4 lines long + public enum TestEnumDefinition + { + Debug, + Info, + Warning, + Error, + Critical + } + + // Class declaration test + public class TestClassDefinition : ITestInterfaceDefinition + { + // Fields + private readonly string _prefix; + private static int _instanceCount = 0; + + // Property declaration tests - each property has clear naming and spans 4+ lines + public string TestPropertyDefinition + { + get; + set; + } + + public TestEnumDefinition TestPropertyWithAccessor + { + get; + private set; + } + + // Auto-implemented property with init accessor (C# 9.0+) + public string TestPropertyWithInit + { + get; + init; + } + + // Required member (C# 11.0+) + public required string TestRequiredProperty + { + get; + set; + } + + // Event declaration test with custom accessors - at least 4 lines long + private EventHandler _testEvent; + public event EventHandler TestEventDefinition + { + add + { + _testEvent += value; + Console.WriteLine("Event handler added"); + } + remove + { + _testEvent -= value; + Console.WriteLine("Event handler removed"); + } + } + + // Delegate declaration test - at least 4 lines long + public delegate void TestDelegateDefinition( + string message, + TestEnumDefinition level, + DateTime timestamp + ); + + // Constructor - at least 4 lines long + public TestClassDefinition(string prefix) + { + _prefix = prefix; + TestPropertyWithAccessor = TestEnumDefinition.Info; + _instanceCount++; + TestPropertyDefinition = "Default Value"; + } + + // Method declaration test - standard method with block body + [TestAttributeDefinition("Interface", 2)] + public void TestInterfaceMethod(string message) + { + var formattedMessage = TestInterfaceFormatMethod(message, TestPropertyWithAccessor); + Console.WriteLine(formattedMessage); + + // Raise event + _testEvent?.Invoke(this, new TestEventArgsDefinition(formattedMessage)); + } + + // Method with expression body - expanded to 4 lines with comments + // This tests expression-bodied methods which have a different syntax + // The => syntax is important to test separately + public string TestInterfaceFormatMethod(string message, TestEnumDefinition level) => + $"[{level}] {_prefix}: {message}"; + + // Static method test - expanded to 4 lines + // This tests static methods which have different modifiers + // Also tests expression-bodied implementation + public static int TestStaticMethodDefinition() => + _instanceCount; + + // Implementation of interface method + public int TestInterfaceCalculateMethod(int x, int y) + { + // Simple calculation + return x + y; + } + + // Generic method test - already 4+ lines + public T TestGenericMethodDefinition(string message) where T : class + { + // Implementation would go here + Console.WriteLine($"Generic method called with: {message}"); + return null; + } + } + + // Event args class + public class TestEventArgsDefinition : EventArgs + { + // Property with only getter + public string Message { get; } + + // Constructor - at least 4 lines + public TestEventArgsDefinition(string message) + { + Message = message; + Console.WriteLine($"Event args created: {message}"); + } + } + + // Struct declaration test - already 4+ lines + public struct TestStructDefinition + { + // Fields + public DateTime Timestamp; + public string Message; + public TestEnumDefinition Level; + + // Constructor + public TestStructDefinition(string message, TestEnumDefinition level) + { + Timestamp = DateTime.Now; + Message = message; + Level = level; + } + + // Method + public override string ToString() + { + return $"{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level}] {Message}"; + } + } + + // Record declaration test (C# 9.0+) - expanded to ensure 4+ lines + public record TestRecordDefinition(string Message, TestEnumDefinition Level, DateTime Timestamp) + { + // Additional members can be added to records + public string FormattedTimestamp => Timestamp.ToString("yyyy-MM-dd HH:mm:ss"); + + // Method in record + public string TestRecordMethodDefinition() + { + return $"{FormattedTimestamp} [{Level}] {Message}"; + } + } + + // Partial class test (first part) - expanded to 4+ lines + public partial class TestPartialClassDefinition + { + // Field in partial class + private Dictionary _storage = new Dictionary(); + + public string TestPartialMethod1(string key) + { + // Implementation would go here + return _storage.ContainsKey(key) ? _storage[key] : string.Empty; + } + } + + // Partial class test (second part) - expanded to 4+ lines + public partial class TestPartialClassDefinition + { + // Another field in partial class + private bool _modified = false; + + public void TestPartialMethod2(string key, string value) + { + // Implementation would go here + _storage[key] = value; + _modified = true; + } + } + + // Static class test - already 4+ lines + public static class TestStaticClassDefinition + { + // Extension method test + public static void TestExtensionMethod1(this ITestInterfaceDefinition logger, string message) + { + logger.TestInterfaceMethod($"DEBUG: {message}"); + } + + // Another extension method + public static void TestExtensionMethod2(this ITestInterfaceDefinition logger, Exception ex) + { + logger.TestInterfaceMethod($"ERROR: {ex.Message}"); + } + } + + // Generic class test - already 4+ lines + public class TestGenericClassDefinition where T : class, new() + { + private List _items = new List(); + + public void TestGenericClassMethod1(T item) + { + _items.Add(item); + } + + public List TestGenericClassMethod2() + { + return _items; + } + + public T TestGenericMethodWithConstraint(TId id) where TId : IEquatable + { + // Implementation would go here + return new T(); + } + } + + // Nested class test - already 4+ lines + public class TestOuterClassDefinition + { + private int _value; + + public TestOuterClassDefinition(int value) + { + _value = value; + } + + // Nested class - expanded to 4+ lines + public class TestNestedClassDefinition + { + private string _nestedField = "Nested"; + + public void TestNestedMethod() + { + Console.WriteLine("Nested class method"); + } + } + } + + // Async method test - already 4+ lines + public class TestAsyncClassDefinition + { + public async Task TestAsyncMethodDefinition(string data) + { + await Task.Delay(100); // Simulate async work + + // Process the data + var result = await TestAsyncPrivateMethod1(data); + + // More async operations + await TestAsyncPrivateMethod2(result); + } + + private async Task TestAsyncPrivateMethod1(string data) + { + await Task.Delay(50); // Simulate async work + return data.ToUpper(); + } + + private async Task TestAsyncPrivateMethod2(string result) + { + await Task.Delay(50); // Simulate async work + // Save the result + } + } + + // Abstract class test - expanded to 4+ lines + public abstract class TestAbstractClassDefinition + { + // Abstract property + public abstract string TestAbstractProperty { get; } + + // Abstract method + public abstract double TestAbstractMethod(); + } + + // Derived classes test - already 4+ lines + public class TestDerivedClass1 : TestAbstractClassDefinition + { + public double TestProperty1 { get; set; } + + // Implementation of abstract property + public override string TestAbstractProperty => "Derived1"; + + public TestDerivedClass1(double value) + { + TestProperty1 = value; + } + + public override double TestAbstractMethod() => Math.PI * TestProperty1 * TestProperty1; + } + + public class TestDerivedClass2 : TestAbstractClassDefinition + { + public double TestProperty2 { get; set; } + public double TestProperty3 { get; set; } + + // Implementation of abstract property + public override string TestAbstractProperty => "Derived2"; + + public TestDerivedClass2(double width, double height) + { + TestProperty2 = width; + TestProperty3 = height; + } + + public override double TestAbstractMethod() => TestProperty2 * TestProperty3; + } +} + +// File-scoped namespace test (C# 10.0+) - expanded to 4+ lines +namespace TestFileScopedNamespaceDefinition +{ + // Class in file-scoped namespace + public class TestFileScopedClassDefinition + { + private string _scopedField = "Scoped"; + + public void TestFileScopedMethod() + { + Console.WriteLine("File-scoped namespace class"); + } + } +} + // LINQ expression test - expanded to 4+ lines + public class TestLinqExpressionDefinition + { + private readonly List _numbers = new List { 1, 2, 3, 4, 5 }; + + public IEnumerable TestLinqMethod() + { + // Multi-line LINQ query expression + var result = from num in _numbers + where num % 2 == 0 + orderby num descending + select num * num; + + return result; + } + } +} +` diff --git a/src/services/tree-sitter/__tests__/fixtures/sample-c.ts b/src/services/tree-sitter/__tests__/fixtures/sample-c.ts new file mode 100644 index 00000000000..41ea927de9c --- /dev/null +++ b/src/services/tree-sitter/__tests__/fixtures/sample-c.ts @@ -0,0 +1,453 @@ +export default String.raw` +// ===== PREPROCESSOR DEFINITIONS ===== + +// Testing preprocessor conditional blocks - at least 4 lines +#ifdef _WIN32 + #define TEST_PATH_SEPARATOR "\\" + #define TEST_LINE_ENDING "\r\n" + #define TEST_OS "windows" +#else + #define TEST_PATH_SEPARATOR "/" + #define TEST_LINE_ENDING "\n" + #define TEST_OS "unix" +#endif + +// Testing nested conditional compilation - at least 4 lines +#if defined(TEST_DEBUG) + #if TEST_DEBUG_LEVEL >= 2 + #define TEST_VERBOSE_LOG 1 + #define TEST_TRACE_ENABLED 1 + #else + #define TEST_VERBOSE_LOG 0 + #define TEST_TRACE_ENABLED 0 + #endif +#endif + +// Testing object-like macro definitions +#define MAX_SIZE 1024 /* Basic size constant */ +#define BUFFER_SIZE ( \ + MAX_SIZE * 2 /* Double the max size */ \ +) /* for safety margin */ + +#define TIMEOUT_MS ( \ + 1000 * /* One second */ \ + 60 * /* One minute */ \ + 5 /* Five minutes total */ \ +) + +// Testing feature-based conditional compilation +#ifndef TEST_FEATURE_DISABLE + #if defined(TEST_FEATURE_ADVANCED) && \ + defined(TEST_FEATURE_EXPERIMENTAL) && \ + (TEST_VERSION_MAJOR > 2) + #define TEST_ENABLE_ADVANCED_FEATURES + #endif +#endif + +// Testing function-like macro - at least 4 lines +#define TEST_MIN(a,b) ( \ + (a) < (b) ? \ + (a) : \ + (b) \ +) + +#define TEST_MAX(a,b) ( \ + (a) > (b) ? \ + (a) : \ + (b) \ +) + +// Testing multi-line macro with conditional compilation +#ifdef TEST_ENABLE_LOGGING + #define TEST_DEBUG_LOG(level, msg, ...) do { \ + if (debug_level >= level) { \ + if (TEST_LOG_TIMESTAMP) { \ + printf("[%s][%lu] " msg "\n", #level, time(NULL), ##__VA_ARGS__); \ + } else { \ + printf("[%s] " msg "\n", #level, ##__VA_ARGS__); \ + } \ + } \ + } while(0) +#else + #define TEST_DEBUG_LOG(level, msg, ...) do {} while(0) +#endif + +// ===== GLOBAL VARIABLES ===== + +// Testing global constant declarations +static const int MAGIC_NUMBER = ( + 0x1234 << 16 | /* High word */ + 0xABCD /* Low word */ +); + +static const char* const BUILD_INFO[] = { + __DATE__, /* Compilation date */ + __TIME__, /* Compilation time */ + "1.0.0", /* Version string */ + "DEBUG" /* Build type */ +}; + +// Testing global struct initialization +static struct config_struct { + int max_connections; /* Connection limit */ + char host[256]; /* Host address */ + double timeout_sec; /* Timeout in seconds */ + int flags; /* Configuration flags */ +} DEFAULT_CONFIG = { + .max_connections = 100, + .host = "localhost", + .timeout_sec = 30.0, + .flags = 0x0F +}; + +// ===== FUNCTION DECLARATIONS ===== + +// Testing function prototype with multiple parameters across lines +void multiline_prototype( + int param1, + char* param2, + float param3, + double param4 +); + +// Testing function prototype with void parameter +/** + * Function prototype that takes no parameters + * Demonstrates void parameter usage + * @return void No return value + */ +void void_param_prototype( + void /* Explicit void parameter */ +); + + +// Testing function prototype with function pointer parameter +void function_pointer_prototype( + void (*callback)(void*), + int priority +); + +// Testing variadic function prototype +int variadic_prototype( + const char* format, + int count, + ... +); + + * Validates the provided configuration structure + * @param config Pointer to configuration structure + * @return int Status code (0 for success) + */ +int test_validate_config(const struct TestConfig* config); + +// Testing function pointer declarations +typedef int (*TEST_COMPARE_FUNC)(const void*, const void*); +extern TEST_COMPARE_FUNC test_get_comparator(int type); + +// Testing variadic function declaration +int test_format_message(const char* format, ...); + +// ===== UNION DEFINITIONS ===== + +// Testing union with multiple data type interpretations +/** + * Union demonstrating type punning and data reinterpretation + * Each field represents a different view of the same memory + */ +union multitype_data_union { + int as_integer; /* Integer view */ + float as_float; /* Float view */ + char as_bytes[4]; /* Raw byte array view */ + void* as_pointer; /* Pointer view */ + double as_double; /* Double view */ +}; + +// Testing union with embedded bitfield struct +union bitfield_union { + struct { + unsigned int flag_one : 1; + unsigned int flag_two : 1; + unsigned int reserved_bits : 30; + } bit_fields; + unsigned int raw_value; +}; + +// ===== STRUCT DEFINITIONS ===== + +// Testing struct with basic field types +/** + * Structure containing fields of different primitive types + * Demonstrates basic field type support + */ +union basic_types_struct { + int integer_field; /* Integer type */ + char string_field[20]; /* Fixed-size array */ + float float_field; /* Float type */ + double double_field; /* Double type */ + void* pointer_field; /* Pointer type */ + unsigned long ulong_field; /* Unsigned long */ +}; + +// Testing struct with nested anonymous struct +struct nested_struct { + char outer_name[50]; + int outer_id; + struct { + char street_name[100]; + char city_name[50]; + int postal_code; + float coordinates[2]; + } address_info; +}; + +// Testing struct with bitfield members +struct bitfield_struct { + unsigned int flag_one : 1; + unsigned int flag_two : 1; + unsigned int value_bits : 6; + unsigned int reserved_bits : 24; +}; + +// Testing struct with function pointer callbacks +struct callback_struct { + void (*test_callback)(const char* message); + int test_priority; + char test_name[32]; + void (*test_error_handler)(int code); +}; + +// ===== FUNCTION DEFINITIONS ===== +// Testing basic function definition with multiple parameter types +int basic_multitype_function( + int param1, + char* param2, + float param3, + double param4 +) { + int result = param1; + return result; +} + +// Testing function with array parameters of different dimensions +void array_param_function( + int single_dim[], + char fixed_size[50], + float multi_dim[4][4], + int size +) { + for (int i = 0; i < size; i++) { + single_dim[i] *= 2; + } +} + +// Testing function with pointer parameters +void pointer_param_function( + int* direct_ptr, + char** ptr_to_ptr, + void* void_ptr, + const int* const_ptr +) { + if (direct_ptr) { + *direct_ptr = 42; + } +} + +// Testing variadic function implementation +int variadic_impl_function( + const char* format, + int count, + ... +) { + va_list args; + va_start(args, count); + int sum = 0; + va_end(args); + return sum; +} + +// Testing function with pointer parameters +void test_pointer_function( + int* test_ptr1, + char** test_ptr2, + struct TestBasicStruct* test_ptr3, + void (*test_callback)(void*) +) { + if (test_ptr1 && test_ptr3) { + test_ptr3->test_field_int = *test_ptr1; + } +} + +// Testing variadic function +#include +int test_variadic_function( + int test_count, + const char* test_format, + ... +) { + va_list args; + va_start(args, test_format); + int sum = 0; + for (int i = 0; i < test_count; i++) { + sum += va_arg(args, int); + } + va_end(args); + return sum; +} + +// ===== ENUM DEFINITIONS ===== + +// Testing enum with sequential values +/** + * Enumeration demonstrating sequential value assignment + * Each value is implicitly incremented from the previous + */ +enum sequential_value_enum { + FIRST = 0, /* Base value */ + SECOND, /* Implicit 1 */ + THIRD, /* Implicit 2 */ + FOURTH, /* Implicit 3 */ + LAST = -1 /* Explicit value */ +}; + +// Testing enum with explicit values +enum explicit_value_enum { + ONE = 1, + TEN = 10, + HUNDRED = 100, + THOUSAND = 1000 +}; + +// Testing enum with mixed values +enum mixed_value_enum { + AUTO_FIRST, /* Implicit 0 */ + EXPLICIT_TEN = 10, /* Explicit 10 */ + AUTO_ELEVEN, /* Implicit 11 */ + EXPLICIT_TWENTY = 20/* Explicit 20 */ +}; +enum TestBasicEnum { + TEST_ENUM_FIRST = 0, /* Initial state */ + TEST_ENUM_SECOND = 1, /* Processing state */ + TEST_ENUM_THIRD = 2, /* Validation state */ + TEST_ENUM_FOURTH = 3, /* Completion state */ +}; + +// ===== TYPEDEF DECLARATIONS ===== + +// Testing typedef for struct with multiple fields +typedef struct { + double x; /* X coordinate */ + double y; /* Y coordinate */ + double z; /* Z coordinate */ + char label[32]; /* Point label */ + unsigned int flags; /* Point flags */ +} point3d_struct_typedef; + +// Testing typedef for function pointer with multiple parameters +typedef void (*event_callback_typedef)( + int event_code, /* Event identifier */ + const char* message, /* Event description */ + void* user_data, /* User context */ + unsigned int flags /* Event flags */ +); + +// Testing typedef for simple type alias +typedef unsigned long long timestamp_typedef; + +// Testing typedef for function pointer array +typedef int (*operation_array_typedef[4])( + int a, + int b, + void* context +); + TEST_ENUM_ERROR = -1 /* Error state */ +}; + +// Testing enum with explicit values +enum TestValuedEnum { + TEST_VALUED_ONE = 1, + TEST_VALUED_TEN = 10, + TEST_VALUED_HUNDRED = 100, + TEST_VALUED_THOUSAND = 1000 +}; + +// ===== TYPEDEF DECLARATIONS ===== + +// Testing typedef for 3D point structure +typedef struct { + double x; /* X coordinate */ + double y; /* Y coordinate */ + double z; /* Z coordinate */ + char label[32]; /* Point label */ + unsigned int flags; /* Point flags */ +} point3d_struct_typedef; + +// Testing typedef for event callback function +typedef void (*event_callback_typedef)( + int event_code, /* Event identifier */ + const char* message, /* Event description */ + void* user_data, /* User context */ + unsigned int flags /* Event flags */ +); + +// Testing typedef for simple type alias +typedef unsigned long long timestamp_typedef; + +// Testing typedef for function pointer array +typedef int (*operation_array_typedef[4])( + int a, + int b, + void* context +); + +// Testing typedef for struct - at least 4 lines +/** + * Typedef struct for metadata + * Used for testing purposes + */ +typedef struct { + double test_x; /* X coordinate */ + double test_y; /* Y coordinate */ + double test_z; /* Z coordinate */ + char test_label[32]; /* Point label */ + unsigned int test_flags; /* Point flags */ + float test_weight; /* Point weight */ +} TestTypedefStruct; + +// Testing typedef for function pointer - at least 4 lines +/** + * Callback function type for event handling + * Used for registering event handlers with configurable parameters + */ +typedef void (*TestTypedefCallback)( + int test_code, /* Event code */ + const char* test_message, /* Event message */ + void* test_data, /* User data */ + unsigned int test_flags, /* Event flags */ + double test_timestamp /* Event timestamp */ +); + +// ===== C11 FEATURES ===== + +// Testing anonymous union in struct +struct anonymous_union_struct { + int type_field; + struct { + union { + struct { + unsigned char blue; + unsigned char green; + unsigned char red; + unsigned char alpha; + }; + unsigned int color; + }; + }; +}; + +// Testing struct with alignment +struct aligned_struct { + char unaligned_field; + _Alignas(8) int aligned_int; + double normal_double; + _Alignas(16) float aligned_float; +};` diff --git a/src/services/tree-sitter/__tests__/fixtures/sample-cpp.ts b/src/services/tree-sitter/__tests__/fixtures/sample-cpp.ts new file mode 100644 index 00000000000..7cba1a7df90 --- /dev/null +++ b/src/services/tree-sitter/__tests__/fixtures/sample-cpp.ts @@ -0,0 +1,179 @@ +export default String.raw` +// Function declaration test - showing prototype over 4 lines +void multiline_function_prototype( + int parameter1, + const std::string& parameter2, + double parameter3 = 0.0, + bool* optional_param = nullptr +); + +// Function implementation test - 4+ lines +void function_with_implementation( + int value, + bool debug = false +) +{ + std::cout << "Processing value: " << value << std::endl; + if (debug) { + std::cout << "Debug mode enabled" << std::endl; + } + value *= 2; +} + +// Struct declaration test - 4+ lines +struct four_field_struct +{ + int field1; + std::string field2; + double field3; + bool field4; +}; + +// Class declaration test - 4+ lines with multiple features +class base_class_definition +{ +public: + virtual void virtual_method() = 0; + virtual ~base_class_definition() = default; +protected: + int protected_member; +}; + +// Union declaration test - 4+ lines +union four_member_union +{ + int integer_value; + float float_value; + char char_value; + double double_value; +}; + +// Enum declaration test - 4+ lines +enum class scoped_enumeration : uint8_t +{ + Value1, + Value2, + Value3, + Value4 +}; + +// Typedef test - 4+ lines with template +typedef std::vector< + std::pair< + std::string, + int + > +> complex_type_definition; + +// Namespace test - 4+ lines +namespace deeply_nested_namespace +{ + namespace inner + { + void nested_function(); + } +} + +// Template class test - 4+ lines +template< + typename T, + typename U = int, + template class Container = std::vector +> +class template_class_definition +{ +public: + T template_method( + U value, + Container container + ); +private: + Container data; +}; + +// Macro definition test - 4+ lines +#define MULTI_LINE_MACRO(x, y) \\ + do { \\ + statement1(x); \\ + if (x > 0) { \\ + statement2(y); \\ + } else { \\ + statement3(y); \\ + } \\ + } while(0) + +// Variable declaration test - 4+ lines +static const std::map< + std::string, + std::vector +> global_variable_definition = { + {"test", {1, 2, 3, 4}} +}; + +// Constructor test - 4+ lines +class constructor_test +{ +public: + constructor_test( + int param1, + std::string param2 + ) : member1(param1), + member2(std::move(param2)) {} +private: + int member1; + std::string member2; +}; + +// Destructor test - 4+ lines +class destructor_test +{ +public: + ~destructor_test() + { + cleanup_resources(); + } +}; + +// Operator overload test - 4+ lines +class operator_test +{ +public: + bool operator==( + const operator_test& other + ) const + { + if (value == other.value) { + return true; + } + return false; + } + + bool operator<( + const operator_test& other + ) const + { + return value < other.value; + } +private: + int value; +}; + +// Friend declaration test - 4+ lines +class friendship_class +{ +private: + friend class friend_class; + friend void friend_function( + friendship_class& + ); +}; + +// Using declaration test - 4+ lines +class using_declaration_test : + private base_class_definition +{ +public: + using base_class_definition::virtual_method; + using size_type = std::size_t; +}; +` diff --git a/src/services/tree-sitter/__tests__/fixtures/sample-css.ts b/src/services/tree-sitter/__tests__/fixtures/sample-css.ts new file mode 100644 index 00000000000..d74163d9b93 --- /dev/null +++ b/src/services/tree-sitter/__tests__/fixtures/sample-css.ts @@ -0,0 +1,97 @@ +export default String.raw` +/* Variable declaration test - at least 4 lines long */ +:root { + --test-variable-definition-primary: #3498db; + --test-variable-definition-secondary: #2ecc71; + --test-variable-definition-accent: #e74c3c; + --test-variable-definition-text: #333333; +} + +/* Import statement test - at least 4 lines long */ +@import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;700&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=Lato:wght@300;400;700&display=swap'); +@import './test-import-definition-variables.css'; + +/* Media query test - at least 4 lines long */ +@media screen and (min-width: 768px) and (max-width: 1024px) { + .test-media-query-definition-container { + padding: 20px; + margin: 10px; + } +} + +/* Keyframe animation test - at least 4 lines long */ +@keyframes test-keyframe-definition-fade { + 0% { + opacity: 0; + transform: translateY(-10px); + } + 100% { + opacity: 1; + transform: translateY(0); + } +} + +/* Animation property test - at least 4 lines long */ +.test-animation-definition { + animation-name: test-keyframe-definition-fade; + animation-duration: 1s; + animation-timing-function: ease-in-out; + animation-fill-mode: forwards; +} + +/* Function test - at least 4 lines long */ +.test-function-definition { + background-color: rgba( + var(--test-variable-definition-primary, 255), + 100, + 200, + 0.5 + ); + transform: translate( + calc(100% - 20px), + calc(50% - 10px) + ); +} + +/* Mixin test (using CSS custom properties as a proxy) - at least 4 lines long */ +.test-mixin-definition { + --button-padding: 10px 15px; + --button-border-radius: 4px; + --button-font-weight: bold; + --button-transition: all 0.3s ease; +} + +/* Basic ruleset test - at least 4 lines long */ +.test-ruleset-definition { + color: var(--test-variable-definition-text); + font-family: 'Open Sans', sans-serif; + font-size: 16px; + line-height: 1.5; +} + +/* Selector test with multiple complex selectors - at least 4 lines long */ +.test-selector-definition:hover, +.test-selector-definition:focus, +.test-selector-definition::before, +.test-selector-definition > .child { + color: var(--test-variable-definition-accent); +} + +/* Nested ruleset test (using nesting syntax) - at least 4 lines long */ +.test-nested-ruleset-definition { + display: flex; + flex-direction: column; + + & > .nested-child { + margin-bottom: 10px; + padding: 15px; + } + + & .deeply-nested { + color: blue; + font-weight: bold; + } +} +` diff --git a/src/services/tree-sitter/__tests__/fixtures/sample-elisp.ts b/src/services/tree-sitter/__tests__/fixtures/sample-elisp.ts new file mode 100644 index 00000000000..e0f21dd4ba6 --- /dev/null +++ b/src/services/tree-sitter/__tests__/fixtures/sample-elisp.ts @@ -0,0 +1,56 @@ +export default ` +;; Function definition with docstring and args +(defun test-function + (arg1 arg2 &optional arg3) + "Docstring explaining function purpose +and providing usage examples." + (let ((result (+ arg1 arg2))) + (when arg3 + (setq result (+ result arg3))) + result)) + +;; Macro definition with pattern matching +(defmacro test-macro + (pattern &rest body) + "Docstring explaining macro purpose +and transformation rules." + \`(cond + ((null ,pattern) nil) + ((atom ,pattern) ,@body) + (t (cons (car ,pattern) + (cdr ,pattern))))) + +;; Variable definition +(defvar test-variable 42 + "A test variable with documentation.") + +;; Constant definition +(defconst test-constant 3.14159 + "Mathematical constant pi.") + +;; Custom form definition +(defcustom test-custom 'default + "A customizable variable." + :type 'symbol + :group 'test-group) + +;; Face definition +(defface test-face + '((t :foreground "red" :weight bold)) + "Face used for testing purposes." + :group 'test-faces) + +;; Advice definition +(defadvice test-advice (around test-advice-function) + "Advice docstring explaining modification." + (let ((old-value (do-something))) + ad-do-it + (unless (equal old-value (do-something)) + (message "Value changed")))) + +;; Group definition +(defgroup test-group nil + "Test customization group." + :group 'tools + :prefix "test-") +` diff --git a/src/services/tree-sitter/__tests__/fixtures/sample-elixir.ts b/src/services/tree-sitter/__tests__/fixtures/sample-elixir.ts new file mode 100644 index 00000000000..5ed6dc9b007 --- /dev/null +++ b/src/services/tree-sitter/__tests__/fixtures/sample-elixir.ts @@ -0,0 +1,117 @@ +export default String.raw` +# Module attribute test - at least 4 lines long +@moduledoc """ +This module demonstrates various Elixir +code structures for testing purposes +with tree-sitter parsing +""" + +# Behaviour definition test - at least 4 lines long +defmodule TestBehaviourDefinition do + @callback test_behaviour_callback( + arg1 :: String.t(), + arg2 :: integer() + ) :: {:ok, any()} | {:error, String.t()} +end + +# Module implementation test - at least 4 lines long +defmodule TestModuleDefinition do + @behaviour TestBehaviourDefinition + + # Attribute test - at least 4 lines long + @test_attribute_definition [ + key1: "value1", + key2: "value2", + key3: "value3" + ] + + # Struct test - at least 4 lines long + defstruct [ + field1: nil, + field2: "", + field3: 0, + field4: %{} + ] + + # Guard test - at least 4 lines long + defguard test_guard_definition(value) + when is_integer(value) and + value > 0 and + value < 100 and + rem(value, 2) == 0 + + # Macro test - at least 4 lines long + defmacro test_macro_definition(opts) do + quote do + require Logger + Logger.info("Macro called with: #{inspect(unquote(opts))}") + unquote(opts) + end + end + + # Protocol implementation test - at least 4 lines long + defimpl String.Chars, + for: TestModuleDefinition do + def to_string(%TestModuleDefinition{ + field1: f1, + field2: f2 + }) do + "TestModule(#{f1}, #{f2})" + end + end + + # Function with multiple clauses test - at least 4 lines long + def test_function_definition( + arg1, + arg2 \\ nil, + opts \\ [] + ) + + def test_function_definition( + arg1, + nil, + opts + ) when is_list(opts) do + {:ok, arg1} + end + + # Pipeline operator test - at least 4 lines long + def test_pipeline_definition(input) do + input + |> String.split(",") + |> Enum.map(&String.trim/1) + |> Enum.filter(&(&1 != "")) + end + + # List comprehension test - at least 4 lines long + def test_comprehension_definition(list) do + for item <- list, + is_integer(item), + item > 0, + do: item * 2 + end + + # Sigil test - at least 4 lines long + def test_sigil_definition do + ~s""" + This is a sigil + that spans multiple + lines for testing + purposes + """ + end +end + +# Test module definition - at least 4 lines long +defmodule TestModuleDefinitionTest do + use ExUnit.Case + + test "test_definition", + %{ + field1: value1, + field2: value2 + } do + assert value1 == value2 + end +end +` diff --git a/src/services/tree-sitter/__tests__/fixtures/sample-embedded_template.ts b/src/services/tree-sitter/__tests__/fixtures/sample-embedded_template.ts new file mode 100644 index 00000000000..d78ea5c273c --- /dev/null +++ b/src/services/tree-sitter/__tests__/fixtures/sample-embedded_template.ts @@ -0,0 +1,88 @@ +export default String.raw` +<%# Multi-line comment block explaining + template purpose and usage + across multiple lines %> + +<%# Function definition block %> +<% def complex_helper(param1, param2) + result = process_data(param1) + format_output(result, param2) + end %> + +<%# Class definition block %> +<% class TemplateHelper + def initialize(options) + @options = options + end + + def render_content + process_template_data + end + end %> + +<%# Module definition block %> +<% module TemplateUtils + def self.format_data(input) + sanitize(input) + end + + def self.validate_input(data) + check_format(data) + end + end %> + +<%# Control structure with nested blocks %> +
+ <% if user.authenticated? %> +

Welcome, <%= user.name %>

+ + <% user.posts.each do |post| %> +
+

<%= post.title %>

+
+ <%= post.content %> +
+ + <% if post.has_comments? %> +
+ <% post.comments.each do |comment| %> +
+ <%= comment.body %> +
+ <% end %> +
+ <% end %> +
+ <% end %> + <% else %> +

Please log in

+ <% end %> +
+ +<%# Helper method definition %> +<% def render_navigation(items) + items.map do |item| %> + + <% end + end %> + +<%# Complex layout structure %> +<% content_for :header do %> +
+ +
+<% end %> + +<%# Yield block with fallback %> +<% content_for :main do %> +
+ <%= yield || render('default_content') %> +
+<% end %> +` diff --git a/src/services/tree-sitter/__tests__/fixtures/sample-go.ts b/src/services/tree-sitter/__tests__/fixtures/sample-go.ts new file mode 100644 index 00000000000..3b761c141eb --- /dev/null +++ b/src/services/tree-sitter/__tests__/fixtures/sample-go.ts @@ -0,0 +1,126 @@ +export default String.raw` +// Package declaration test - at least 4 lines long +package main + +import ( + "fmt" + "sync" + "time" +) + +// Const block test - at least 4 lines long +const ( + TestConstDefinition1 = "test1" + TestConstDefinition2 = "test2" + TestConstDefinition3 = "test3" + TestConstDefinition4 = 42 +) + +// Var block test - at least 4 lines long +var ( + TestVarDefinition1 string = "var1" + TestVarDefinition2 int = 42 + TestVarDefinition3 bool = true + TestVarDefinition4 []int = []int{1, 2, 3} +) + +// Interface declaration test - at least 4 lines long +type TestInterfaceDefinition interface { + TestInterfaceMethod1( + param1 string, + param2 int, + ) error + TestInterfaceMethod2() string +} + +// Struct declaration test - at least 4 lines long +type TestStructDefinition struct { + TestField1 string + TestField2 int + TestField3 bool + testField4 []string +} + +// Type declaration test - at least 4 lines long +type TestTypeDefinition struct { + sync.Mutex + data map[string]interface{} + ch chan string + done chan struct{} +} + +// Function declaration test - at least 4 lines long +func TestFunctionDefinition( + param1 string, + param2 int, + param3 bool, +) error { + return nil +} + +// Method declaration test - at least 4 lines long +func (t *TestStructDefinition) TestMethodDefinition( + param1 string, + param2 int, +) ( + result string, + err error, +) { + return "", nil +} + +// Channel test - at least 4 lines long +func TestChannelDefinition( + input chan string, + output chan<- int, + done <-chan struct{}, +) { + select { + case msg := <-input: + output <- len(msg) + case <-done: + return + } +} + +// Goroutine test - at least 4 lines long +func TestGoroutineDefinition() { + ch := make(chan string) + done := make(chan struct{}) + go func() { + time.Sleep(time.Second) + ch <- "hello" + close(done) + }() +} + +// Defer test - at least 4 lines long +func TestDeferDefinition() { + file := createFile() + defer func() { + file.Close() + fmt.Println("file closed") + }() +} + +// Select test - at least 4 lines long +func TestSelectDefinition( + ch1, ch2 <-chan string, + done chan struct{}, +) { + select { + case msg1 := <-ch1: + fmt.Println("received from ch1:", msg1) + case msg2 := <-ch2: + fmt.Println("received from ch2:", msg2) + case <-done: + fmt.Println("done") + return + } +} + +// Helper function to avoid undefined error +func createFile() interface{} { + return nil +} +` diff --git a/src/services/tree-sitter/__tests__/fixtures/sample-html.ts b/src/services/tree-sitter/__tests__/fixtures/sample-html.ts new file mode 100644 index 00000000000..44392ff451b --- /dev/null +++ b/src/services/tree-sitter/__tests__/fixtures/sample-html.ts @@ -0,0 +1,88 @@ +export const sampleHtmlContent = ` + + + + + HTML Sample + + + + + +
+

Element Test

+
+ + + + + + + +
+ This is a text node + spanning multiple + lines to meet the + 4-line requirement +
+ +
+

Fragment test

+ Multiple elements + In a fragment + Structure +
+ + Test void element + +
+ +
+
+            Raw text content
+            preserving whitespace
+            and formatting
+            exactly as written
+        
+
+ +
+
+
+
+ Deeply nested content +
+
+
+
+ + +` diff --git a/src/services/tree-sitter/__tests__/fixtures/sample-java.ts b/src/services/tree-sitter/__tests__/fixtures/sample-java.ts new file mode 100644 index 00000000000..80ecaf2da2c --- /dev/null +++ b/src/services/tree-sitter/__tests__/fixtures/sample-java.ts @@ -0,0 +1,193 @@ +export default String.raw` +// Module declaration test - at least 4 lines long +module test.module.definition { + requires java.base; + requires transitive java.desktop; + exports test.module.api; +} +package test.package.definition; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.time.LocalDateTime; + +// Annotation declaration test - at least 4 lines long +@Target({ + ElementType.TYPE, + ElementType.METHOD, + ElementType.FIELD +}) +@Retention(RetentionPolicy.RUNTIME) +public @interface TestAnnotationDefinition { + String value() default ""; + int priority() default 0; + boolean enabled() default true; + Class[] types() default {}; +} + +// Interface declaration test - at least 4 lines long +public interface TestInterfaceDefinition> { + // Interface method declarations + void testInterfaceMethod( + String message, + T data + ); + + // Default method in interface - 4+ lines + default String testInterfaceDefaultMethod( + String input, + T data + ) { + return String.format("%s: %s", input, data.toString()); + } +} + +// Enum declaration test - at least 4 lines long +public enum TestEnumDefinition { + DEBUG(0, "Debug Level"), + INFO(1, "Info Level"), + WARNING(2, "Warning Level"), + ERROR(3, "Error Level"); + + private final int level; + private final String description; + + TestEnumDefinition( + int level, + String description + ) { + this.level = level; + this.description = description; + } +} + +// Class declaration test with generic type and implementation +@TestAnnotationDefinition( + value = "test", + priority = 1, + enabled = true +) +public class TestClassDefinition> + implements TestInterfaceDefinition { + + // Field declarations - expanded to 4+ lines with annotations + @TestAnnotationDefinition( + value = "field", + priority = 2 + ) + private final String prefix; + private static int instanceCount = 0; + + // Constructor - at least 4 lines long + public TestClassDefinition( + String prefix, + T initialData + ) { + this.prefix = prefix; + this.data = initialData; + instanceCount++; + } + + // Method implementation - at least 4 lines long + @Override + public void testInterfaceMethod( + String message, + T data + ) { + System.out.println(testInterfaceDefaultMethod(message, data)); + } + + // Generic method test - at least 4 lines long + public > R testGenericMethodDefinition( + Function converter, + T input, + R defaultValue + ) { + return input != null ? converter.apply(input) : defaultValue; + } + + // Lambda expression test - at least 4 lines long + private final Function testLambdaDefinition = ( + String input + ) -> { + if (input == null || input.isEmpty()) { + return 0; + } + return input.length(); + }; +} + +// Record declaration test - at least 4 lines long +public record TestRecordDefinition( + String message, + TestEnumDefinition level, + LocalDateTime timestamp, + Map attributes +) { + // Compact constructor + public TestRecordDefinition { + Objects.requireNonNull(message); + Objects.requireNonNull(level); + } + + // Method in record - 4+ lines + public String formatMessage() { + return String.format( + "[%s] %s (%s)", + level, + message, + timestamp + ); + } +} + +// Abstract class test - at least 4 lines long +public abstract class TestAbstractClassDefinition { + protected final T data; + + protected TestAbstractClassDefinition( + T data + ) { + this.data = data; + } + + // Abstract method + public abstract String testAbstractMethod( + String input, + T data + ); +} + +// Inner class test - at least 4 lines long +public class TestOuterClassDefinition { + private int value; + + public class TestInnerClassDefinition { + private String innerField; + + public TestInnerClassDefinition( + String field + ) { + this.innerField = field; + } + + public void testInnerMethod() { + System.out.println( + String.format("Value: %d, Inner: %s", value, innerField) + ); + } + } + + // Static nested class - 4+ lines + public static class TestStaticNestedClassDefinition { + private final String nestedField; + + public TestStaticNestedClassDefinition( + String field + ) { + this.nestedField = field; + } + } +} +` diff --git a/src/services/tree-sitter/__tests__/fixtures/sample-javascript.ts b/src/services/tree-sitter/__tests__/fixtures/sample-javascript.ts new file mode 100644 index 00000000000..db5afb98bec --- /dev/null +++ b/src/services/tree-sitter/__tests__/fixtures/sample-javascript.ts @@ -0,0 +1,165 @@ +export default String.raw` +// Import statements test - inherently single-line, exempt from 4-line requirement +import React, { useState, useEffect } from 'react'; +import { render } from 'react-dom'; +import * as utils from './utils'; + +// Function declaration test - standard function with block body +function testFunctionDefinition( + param1, + param2, + param3 +) { + const result = param1 + param2; + return result * param3; +} + +// Async function test +async function testAsyncFunctionDefinition( + url, + options, + timeout +) { + const response = await fetch(url, options); + const data = await response.json(); + return data; +} + +// Generator function test +function* testGeneratorFunctionDefinition( + start, + end, + step +) { + for (let i = start; i <= end; i += step) { + yield i; + } +} + +// Arrow function test +const testArrowFunctionDefinition = ( + param1, + param2, + callback +) => { + const result = callback(param1); + return result + param2; +}; + +// Class declaration test +class TestClassDefinition { + // Class field declarations + #privateField = 'private'; + static staticField = 'static'; + + constructor( + name, + value + ) { + this.name = name; + this.value = value; + } + + // Method definition + testMethodDefinition( + param1, + param2 + ) { + return param1 + param2; + } + + // Static method + static testStaticMethodDefinition( + input, + multiplier + ) { + return input * multiplier; + } + + // Getter/Setter test + get testGetterDefinition() { + return this.#privateField + + this.name + + this.value; + } + + set testSetterDefinition( + newValue + ) { + this.value = newValue; + this.#privateField = 'modified'; + } +} + +// Object literal test +const testObjectLiteralDefinition = { + property1: 'value1', + property2: 'value2', + + methodInObject( + param + ) { + return param + this.property1; + }, + + get computedProperty() { + return this.property1 + + this.property2; + } +}; + +// JSX element test +const testJsxElementDefinition = ( + props +) => { + return ( +
+
+ {props.title} +
+
+ {props.children} +
+
+ ); +}; + +// Decorator test (requires experimental features) +function testDecoratorDefinition( + target, + context +) { + return function(...args) { + console.log('Decorator called'); + return target.apply(this, args); + }; +} + +// Class with decorator +@testDecoratorDefinition +class TestDecoratedClassDefinition { + constructor( + name, + type + ) { + this.name = name; + this.type = type; + } + + // Decorated method test + @testDecoratorDefinition + testDecoratedMethodDefinition( + param1, + param2, + options = {} + ) { + const result = param1 + param2; + console.log('Method called with options:', options); + return result; + } +} + +// Module export test - inherently single-line, exempt from 4-line requirement +export { testFunctionDefinition, TestClassDefinition }; +export default TestDecoratedClassDefinition; +` diff --git a/src/services/tree-sitter/__tests__/fixtures/sample-json.ts b/src/services/tree-sitter/__tests__/fixtures/sample-json.ts new file mode 100644 index 00000000000..babb4aa7a4d --- /dev/null +++ b/src/services/tree-sitter/__tests__/fixtures/sample-json.ts @@ -0,0 +1,108 @@ +export default String.raw`{ + // Basic value types object + "basic_value_types": { + "string_value": "This is a string with escapes: \n\t\"", + "integer_value": 1000000, + "float_value": 42.5, + "boolean_value": true, + "null_value": null + }, + + // Deeply nested object structure + "nested_object_structure": { + "level1": { + "level2": { + "level3": { + "string_key": "nested_string_value", + "number_key": 12345, + "object_key": { + "inner_key": "inner_value" + } + } + } + } + }, + + // Array structures + "array_structures": { + "string_array": [ + "value1", + "value2", + "value3", + "value4", + "value5" + ], + "mixed_type_array": [ + 100, + "string_value", + false, + null, + { "object_key": "object_value" } + ] + }, + + // Array of objects + "object_array": [ + { + "object_id": 1, + "object_data": { + "timestamp": "2024-01-01", + "updated_at": "2024-01-02" + }, + "object_state": "active" + }, + { + "object_id": 2, + "object_data": { + "timestamp": "2024-01-03", + "updated_at": "2024-01-04" + }, + "object_state": "inactive" + } + ], + + // Mixed nesting with arrays and objects + "mixed_nesting_structure": { + "config": { + "items": [ + { + "item_name": "item1", + "item_enabled": true, + "item_settings": { + "options": ["opt1", "opt2"], + "timeout_sec": 3600 + } + }, + { + "item_name": "item2", + "item_enabled": false, + "item_settings": { + "options": ["opt3", "opt4"], + "timeout_sec": 7200 + } + } + ] + } + }, + + // All value types in one object + "all_value_types": { + "string_key": "string_value", + "number_key": 123.45, + "boolean_key": true, + "null_key": null, + "array_key": [1, 2, 3], + "object_key": { + "nested_key": "nested_value" + } + }, + + // Special string content + "string_special_content": { + "newlines": "Line 1\nLine 2\tTabbed\rCarriage Return", + "unicode": "Unicode chars: 世界", + "quoted": "Text with \"quoted content\"", + "windows_path": "C:\\Program Files\\App", + "url_path": "http://example.com/path/to/resource" + } +}` diff --git a/src/services/tree-sitter/__tests__/fixtures/sample-kotlin.ts b/src/services/tree-sitter/__tests__/fixtures/sample-kotlin.ts new file mode 100644 index 00000000000..2f8b59c11b7 --- /dev/null +++ b/src/services/tree-sitter/__tests__/fixtures/sample-kotlin.ts @@ -0,0 +1,403 @@ +export default String.raw` +// Package declaration test - at least 4 lines long +@file:JvmName("TestFileDefinition") +package com.example.test.definitions + +// Import declarations test - at least 4 lines long +import kotlinx.coroutines.* +import kotlinx.coroutines.flow.* +import kotlin.math.sqrt +import kotlin.properties.Delegates + +// Abstract class declaration test - at least 4 lines long +abstract class TestAbstractClassDefinition { + // Abstract property test + abstract val abstractPropertyDefinition: String + + // Abstract method test + abstract fun abstractMethodDefinition(): String + + // Open method test with implementation + open fun concreteMethodDefinition( + param1: String, + param2: Int + ): Int { + return param2 + param1.length + } +} + +// Interface declaration test - at least 4 lines long +interface TestInterfaceDefinition { + // Interface property test + val interfacePropertyDefinition: String + + // Required method test + fun requiredMethodDefinition( + param1: String, + param2: Int + ): Boolean + + // Default method test + fun defaultMethodDefinition( + message: String = "default" + ): String { + return "Default implementation: $message" + } +} + +// Enum class declaration test - at least 4 lines long +enum class TestEnumClassDefinition( + val enumValue: Int, + val enumDescription: String +) { + FIRST_ENUM(1, "First") { + override fun describeEnumDefinition(): String { + return "Enum value: $enumValue, Description: $enumDescription" + } + }, + SECOND_ENUM(2, "Second") { + override fun describeEnumDefinition(): String { + return "Enum value: $enumValue, Description: $enumDescription" + } + }; + + abstract fun describeEnumDefinition(): String + + fun getEnumValueDefinition(): Int = enumValue +} + +// Type alias declaration test - at least 4 lines long +typealias TestTypeAliasDefinition = ( + data: T, + metadata: Map +) -> Unit where T : Any + +// Annotation class declaration test - at least 4 lines long +@Target( + AnnotationTarget.CLASS, + AnnotationTarget.FUNCTION, + AnnotationTarget.PROPERTY +) +annotation class TestAnnotationClassDefinition( + val annotationName: String, + val annotationValue: Int = 0, + val annotationEnabled: Boolean = true +) + +// Constructor declaration test - at least 4 lines long +@TestAnnotationClassDefinition("constructor-test") +class TestConstructorDefinition( + val constructorParam1: String, + private val constructorParam2: Int +) { + private var constructorField1: String? = null + private var constructorField2: Int = 0 + + // Secondary constructor test + constructor( + param1: String, + param2: Int, + param3: String + ) : this(param1, param2) { + this.constructorField1 = param3 + this.constructorField2 = param2 * 2 + } + + // Another secondary constructor test + constructor( + param1: String, + param2: Int, + param3: String, + param4: Boolean + ) : this(param1, param2, param3) { + if (param4) { + constructorField2 *= 2 + } + } +} + +// Property declaration test with accessors - at least 4 lines long +class TestPropertyDefinition { + // Property with private setter + var propertyWithPrivateSetter: Int = 0 + private set(value) { + if (value >= 0) { + field = value + } + } + + // Property with custom accessors + var propertyWithCustomAccessors: String = "" + get() = field.uppercase() + set(value) { + field = "Custom: $value" + } + + // Property with backing field + private var _propertyWithBackingField: String = "inactive" + var propertyWithBackingField: String + get() = "Status: $_propertyWithBackingField" + set(value) { + _propertyWithBackingField = value.lowercase() + } + + // Delegated property test + var delegatedPropertyDefinition: Int by Delegates.observable(0) { + property, oldValue, newValue -> + println("$property changed from $oldValue to $newValue") + } +} + +// Nested class declaration test - at least 4 lines long +class TestOuterClassDefinition( + private val outerParam1: String, + private val outerParam2: Int +) { + private val outerPropertyDefinition: String = "outer" + + // Inner class test + inner class TestInnerClassDefinition( + private val innerParam: String + ) { + fun innerMethodDefinition(): String { + return "$innerParam: $outerPropertyDefinition" + } + } + + // Nested class test + class TestNestedClassDefinition( + private val nestedParam: String + ) { + fun nestedMethodDefinition(): String { + return "Nested: $nestedParam" + } + } + + // Companion object test + companion object TestCompanionDefinition { + const val COMPANION_CONSTANT = "constant" + + fun companionMethodDefinition(): String { + return "Companion method" + } + } +} + +// Data class declaration test - at least 4 lines long +data class TestDataClassDefinition( + val dataClassParam1: T, + val dataClassParam2: (T) -> R, + val dataClassParam3: Map = mapOf(), + val dataClassParam4: List = listOf() +) where T : Any, R : Any { + + fun dataClassMethodDefinition(): R { + return dataClassParam2(dataClassParam1) + } + + fun dataClassListMethodDefinition(): List { + return dataClassParam4.map(dataClassParam2) + } +} + +// Extension function declaration test - at least 4 lines long +fun String.testExtensionFunctionDefinition( + extensionParam1: String, + extensionParam2: String = "", + extensionParam3: (String) -> String = { it } +): String { + val modified = "$extensionParam1$this$extensionParam2" + return extensionParam3(modified).trim() +} + +// Infix function declaration test - at least 4 lines long +infix fun Int.testInfixFunctionDefinition( + infixParam: Int +): Int { + val multiplier = if (infixParam > 0) 2 else 1 + return this + infixParam * multiplier +} + +// Flow class declaration test - at least 4 lines long +class TestFlowClassDefinition { + private val _stateFlowDefinition = MutableStateFlow("") + val stateFlowDefinition: StateFlow = _stateFlowDefinition.asStateFlow() + + fun testFlowCollectionDefinition( + count: Int = 5, + delayTime: Long = 100 + ): Flow = flow { + for (i in 1..count) { + emit(i) + delay(delayTime) + } + } + + fun updateStateFlowDefinition( + newValue: String + ) { + _stateFlowDefinition.value = newValue + } +} + +// Suspend function declaration test - at least 4 lines long +class TestCoroutineClassDefinition { + private val coroutineScope = CoroutineScope( + Dispatchers.Default + SupervisorJob() + ) + + suspend fun testSuspendFunctionDefinition( + items: List, + processDelay: Long = 100 + ): List = coroutineScope { + items.map { item -> + async { + processSuspendItemDefinition( + item, + processDelay + ) + } + }.awaitAll() + } + + private suspend fun processSuspendItemDefinition( + item: String, + delay: Long + ): String { + delay(delay) + return "Processed suspend item: $item" + } +} + +// Sealed interface declaration test - at least 4 lines long +sealed interface TestSealedInterfaceDefinition { + val interfaceMetadata: Map + + data class SealedSuccess( + val successData: T, + override val interfaceMetadata: Map + ) : TestSealedInterfaceDefinition + + data class SealedError( + val errorData: Throwable, + override val interfaceMetadata: Map + ) : TestSealedInterfaceDefinition + + class SealedLoading( + override val interfaceMetadata: Map = mapOf() + ) : TestSealedInterfaceDefinition +} + +// Object declaration test - at least 4 lines long +object TestObjectDefinition { + private var objectCount: Int by lazy { + calculateObjectCountDefinition() + } + + private fun calculateObjectCountDefinition(): Int { + return (1..10).sum() + } + + val objectDelegatedString by lazy { + val prefix = "Computed" + val value = objectCount * 2 + "$prefix string value: $value" + } + + fun getObjectCountDefinition(): Int { + return objectCount + } +} + +// Operator overloading test - at least 4 lines long +data class TestOperatorDefinition( + val operatorValue: Int, + val operatorName: String = "default" +) { + operator fun plus( + other: TestOperatorDefinition + ): TestOperatorDefinition { + val otherName = other.operatorName + return TestOperatorDefinition( + operatorValue + other.operatorValue, + "$operatorName + $otherName" + ) + } + + operator fun invoke( + multiplier: Int + ): TestOperatorDefinition { + return TestOperatorDefinition( + operatorValue * multiplier, + "$operatorName * $multiplier" + ) + } +} + +// Higher-order function declaration test - at least 4 lines long +fun TestOperatorDefinition.testHigherOrderFunctionDefinition( + param1: String, + param2: Int, + operation: TestOperatorDefinition.(String, Int) -> Int +): Int { + return this.operation(param1, param2) +} + +// Suspend function with Flow declaration test - at least 4 lines long +suspend fun testSuspendFlowFunctionDefinition( + scope: CoroutineScope, + timeout: Long = 1000L, + maxCount: Int = 10 +): Flow = flow { + var count = 0 + while (currentCoroutineContext().isActive && count < maxCount) { + val message = buildString { + append("Count: ") + append(count) + append(", Timeout: ") + append(timeout) + } + emit(message) + count++ + delay(timeout) + } +} + +// Sealed class declaration test - at least 4 lines long +sealed class TestSealedClassDefinition { + abstract val sealedProperty: String + + data class SealedSubclassOneDefinition( + val subclassValue: String, + override val sealedProperty: String + ) : TestSealedClassDefinition() + + class SealedSubclassTwoDefinition( + override val sealedProperty: String + ) : TestSealedClassDefinition() { + fun subclassMethod(): String { + return "Subclass Two: $sealedProperty" + } + } + + object SealedSubclassThreeDefinition : TestSealedClassDefinition() { + override val sealedProperty: String = "Object Subclass" + + fun objectMethod(): String { + return "Subclass Three: $sealedProperty" + } + } +} + +// Function type with receiver declaration test - at least 4 lines long +fun TestSealedClassDefinition.testReceiverFunctionDefinition( + receiverParam1: String, + receiverParam2: Int, + block: TestSealedClassDefinition.( + String, + Int + ) -> String +): String { + return this.block(receiverParam1, receiverParam2) +} +` diff --git a/src/services/tree-sitter/__tests__/fixtures/sample-lua.ts b/src/services/tree-sitter/__tests__/fixtures/sample-lua.ts new file mode 100644 index 00000000000..4d22199a0f7 --- /dev/null +++ b/src/services/tree-sitter/__tests__/fixtures/sample-lua.ts @@ -0,0 +1,138 @@ +export default String.raw` +-- Function declaration test - at least 4 lines long +function test_function( + arg1, + arg2, + arg3 +) + print("This is a test function") + return arg1 + arg2 + arg3 +end + +-- Local function declaration test - at least 4 lines long +local function test_local_function( + param1, + param2, + param3 +) + local result = param1 * param2 * param3 + print("Local function result:", result) + return result +end + +-- Table with method declaration test - at least 4 lines long +local test_table_with_methods = { + data = "test data", + + test_method = function( + self, + param + ) + print("Method called with:", param) + return self.data .. " " .. param + end +} + +-- Table declaration test - at least 4 lines long +local test_table = { + name = "test table", + value = 42, + nested = { + key = "nested value" + } +} + +-- Array table declaration test - at least 4 lines long +local test_array_table = { + "first", + "second", + "third", + "fourth" +} + +-- If statement test - at least 4 lines long +local test_if_statement_var = 10 +if test_if_statement_var > 5 then + print("Greater than 5") + test_if_statement_var = test_if_statement_var + 1 +elseif test_if_statement_var < 5 then + print("Less than 5") + test_if_statement_var = test_if_statement_var - 1 +else + print("Equal to 5") + test_if_statement_var = 5 +end + +-- Numeric for loop test - at least 4 lines long +for test_for_loop_index = 1, 10, 2 do + print("Loop index:", test_for_loop_index) + if test_for_loop_index > 5 then + print("More than halfway") + end +end + +-- Generic for loop with pairs - at least 4 lines long +for test_for_in_loop_key, test_for_in_loop_value in pairs(test_table) do + print( + "Key:", test_for_in_loop_key, + "Value:", test_for_in_loop_value + ) +end + +-- While loop test - at least 4 lines long +local test_while_loop_counter = 0 +while test_while_loop_counter < 5 do + print("Counter:", test_while_loop_counter) + test_while_loop_counter = test_while_loop_counter + 1 + if test_while_loop_counter == 3 then + print("Halfway there") + end +end + +-- Repeat until loop test - at least 4 lines long +local test_repeat_until_counter = 10 +repeat + print("Counting down:", test_repeat_until_counter) + test_repeat_until_counter = test_repeat_until_counter - 1 + if test_repeat_until_counter == 5 then + print("Halfway there") + end +until test_repeat_until_counter == 0 + +-- Do block test - at least 4 lines long +do + local test_do_block_var = "local to do block" + print("Inside do block") + print("Using local var:", test_do_block_var) + test_function(1, 2, 3) +end + +-- Variable declaration test - at least 4 lines long +test_variable_declaration = + "This is a global variable" .. + " with a long string" .. + " split across multiple lines" + +-- Local variable declaration test - at least 4 lines long +local test_local_variable = + "This is a local variable" .. + " with a long string" .. + " split across multiple lines" + +-- Require statement - cannot be 4 lines naturally, but important to test +local test_require = require("module_name") + +-- Module definition - at least 4 lines long +local test_module = {} + +function test_module.test_module_function( + arg1, + arg2 +) + return arg1 + arg2 +end + +test_module.test_module_variable = "module variable" + +return test_module +` diff --git a/src/services/tree-sitter/__tests__/fixtures/sample-ocaml.ts b/src/services/tree-sitter/__tests__/fixtures/sample-ocaml.ts new file mode 100644 index 00000000000..7b52b74cef8 --- /dev/null +++ b/src/services/tree-sitter/__tests__/fixtures/sample-ocaml.ts @@ -0,0 +1,66 @@ +export const sampleOCaml = ` +(* Module with signature *) +module StringSet : sig + type t + val empty: t + val add: string -> t -> t + val mem: string -> t -> bool +end = struct + type t = string list + let empty = [] + let add x s = x :: s + let mem = List.mem +end + +(* Functor definition *) +module OrderedMap (Key: sig + type t + val compare: t -> t -> int +end) = struct + type 'a t = (Key.t * 'a) list + let empty = [] + let add k v map = (k, v) :: map +end + +(* Variant type definition *) +type shape = + | Rectangle of float * float (* width * height *) + | Circle of float (* radius *) + | Triangle of float * float * float (* sides *) + +(* Record type definition *) +type person = { + name: string; + age: int; + address: string option; + phone: string list; +} + +(* Pattern matching function *) +let rec process_list = function + | [] -> None + | x :: xs when x > 0 -> Some x + | _ :: xs -> process_list xs + +(* Multi-argument function *) +let calculate_area ~width ~height ?(margin=0) ?(padding=0) () = + let total_width = width + (2 * margin) + (2 * padding) in + let total_height = height + (2 * margin) + (2 * padding) in + total_width * total_height + +(* Class definition with inheritance *) +class virtual ['a] container = object (self) + val mutable items : 'a list = [] + method virtual add : 'a -> unit + method get_items = items + method clear = items <- [] +end + +(* Object expression *) +let make_counter initial = object + val mutable count = initial + method increment = count <- count + 1 + method decrement = count <- count - 1 + method get_count = count +end +` diff --git a/src/services/tree-sitter/__tests__/fixtures/sample-php.ts b/src/services/tree-sitter/__tests__/fixtures/sample-php.ts new file mode 100644 index 00000000000..99bfabba1ca --- /dev/null +++ b/src/services/tree-sitter/__tests__/fixtures/sample-php.ts @@ -0,0 +1,335 @@ +export default String.raw`standardPrivateProperty = $standardPromotedProperty; + $this->standardProtectedProperty = $standardPromotedProtected; + } + + // Standard method with multiple parameters and return type + public function standardMethodDefinition( + string $standardParam1, + array $standardParam2 = [], + ?int $standardParam3 = null + ): void { + $this->standardPrivateProperty = $standardParam1; + $this->standardNullableProperty = $standardParam2; + } +} + +// Interface declaration test - at least 4 lines long +interface StandardInterfaceDefinition +{ + // Method with class type hint + public function standardInterfaceMethodWithClass( + StandardClassDefinition $standardParam1, + string $standardParam2 + ): array; + + // Method with nullable return + public function standardInterfaceMethodNullable( + int $standardParam1, + bool $standardParam2 = true + ): ?string; + + // Method with void return + public function standardInterfaceMethodVoid( + string $standardParam + ): void; + + // Method with mixed return (PHP 8.0+) + public function standardInterfaceMethodMixed( + mixed $standardParam + ): mixed; +} + +// Trait declaration test - at least 4 lines long +trait StandardTraitDefinition +{ + // Trait properties + private string $standardTraitProperty = ''; + protected array $standardTraitConfig = []; + + // Trait method with visibility modifier + protected function standardTraitMethod( + int $standardParam = 0, + bool $standardFlag = false, + ?string $standardOptional = null + ): string { + // Method implementation + $this->standardTraitProperty = (string)$standardParam; + return $this->standardTraitProperty; + } + + // Abstract method in trait + abstract protected function standardTraitAbstractMethod(): void; +} + +// Enum declaration test (PHP 8.1+) - at least 4 lines long +enum StandardEnumDefinition: string +{ + // Enum cases with values + case PERMISSION_READ = 'read'; + case PERMISSION_WRITE = 'write'; + case PERMISSION_EXECUTE = 'execute'; + case PERMISSION_DELETE = 'delete'; + + // Enum method using match expression + public function standardEnumMethod(): array + { + return match($this) { + self::PERMISSION_READ => ['read'], + self::PERMISSION_WRITE => ['read', 'write'], + self::PERMISSION_EXECUTE => ['read', 'execute'], + self::PERMISSION_DELETE => ['read', 'write', 'delete'], + }; + } + + // Static enum method + public static function standardEnumFromString( + string $permission + ): ?self { + return match($permission) { + 'read' => self::PERMISSION_READ, + 'write' => self::PERMISSION_WRITE, + 'execute' => self::PERMISSION_EXECUTE, + 'delete' => self::PERMISSION_DELETE, + default => null + }; + } +} + +// Abstract class declaration test - at least 4 lines long +#[StandardAttributeDefinition( + description: 'Abstract base class', + priority: 2, + tags: ['abstract', 'base'] +)] +abstract class StandardAbstractClassDefinition +{ + // Class constants + protected const STANDARD_STATUS_ACTIVE = 'active'; + protected const STANDARD_STATUS_INACTIVE = 'inactive'; + + // Static property with type + private static string $standardStaticProperty = ''; + + // Constructor with promoted properties + public function __construct( + private string $standardPromotedProperty, + protected readonly int $standardReadonlyProperty, + public array $standardConfig = [] + ) { + self::$standardStaticProperty = $standardPromotedProperty; + $this->validateConfig(); + } + + // Abstract method declaration + abstract public function standardAbstractMethod( + string $standardParam, + array $standardOptions = [] + ): string; + + // Static method with return type + public static function standardStaticMethod( + string $standardValue + ): string { + self::$standardStaticProperty = $standardValue; + return self::$standardStaticProperty; + } + + // Protected validation method + protected function validateConfig(): void + { + if (empty($this->standardConfig)) { + throw new InvalidArgumentException('Config cannot be empty'); + } + } +} + +// Final class declaration test - at least 4 lines long +#[StandardAttributeDefinition( + description: 'Final implementation class', + priority: 3, + tags: ['final', 'implementation'] +)] +final class StandardFinalClassDefinition extends StandardAbstractClassDefinition +{ + // Implementation of abstract method + public function standardAbstractMethod( + string $standardParam, + array $standardOptions = [] + ): string { + return sprintf( + '%s: %s', + $this->standardPromotedProperty, + $standardParam + ); + } + + // Method with union types (PHP 8.0+) + public function standardUnionTypesMethod( + string|int|float $standardParam, + bool $standardFlag = false + ): string|int { + return $standardFlag ? (string)$standardParam : (int)$standardParam; + } + + // Method with intersection types (PHP 8.1+) + public function standardIntersectionTypesMethod( + Countable&Iterator $standardParam, + bool $standardReturnCount = true + ): int { + return $standardReturnCount ? + count($standardParam) : + iterator_count($standardParam); + } +} + +// Anonymous class declaration test - at least 4 lines long +$standardAnonymousClass = new class( + standardId: 'anonymous_1', + standardConfig: ['type' => 'anonymous'] +) extends StandardClassDefinition +{ + public function __construct( + private string $standardId, + private array $standardConfig + ) { + parent::__construct( + standardPromotedProperty: $standardId, + standardPromotedPublic: $standardConfig + ); + } + + public function standardAnonymousMethod(): string + { + return sprintf( + 'Anonymous[%s]: %s', + $this->standardId, + json_encode($this->standardConfig) + ); + } +}; + +// Global function declaration test - at least 4 lines long +function standardGlobalFunction( + string $standardParam1, + ?array $standardParam2 = null, + int $standardParam3 = 0, + bool $standardFlag = false +): mixed { + // Function implementation with multiple returns + if ($standardFlag) { + return array_merge( + [$standardParam1], + $standardParam2 ?? [] + ); + } + + return $standardParam2 ?? $standardParam1; +} + +// Arrow function declaration test - at least 4 lines long +$standardArrowFunction = fn( + int $standardX, + int $standardY, + float $standardMultiplier = 1.0 +): float => + ($standardX + $standardY) * $standardMultiplier; + +// Heredoc syntax test - at least 4 lines long +$standardHeredocContent = << +
+

Standard Component Title

+ +
+
+

Standard paragraph with multiple lines + to ensure proper parsing of heredoc + syntax in PHP code samples

+
+ +HTML; + +// Nowdoc syntax test - at least 4 lines long +$standardNowdocContent = <<<'SQL' +WITH standard_cte AS ( + SELECT + column1, + column2, + COUNT(*) as record_count, + MAX(updated_at) as last_update + FROM standard_table + WHERE status = 'active' + AND created_at >= CURRENT_DATE - INTERVAL '30 days' + GROUP BY + column1, + column2 + HAVING COUNT(*) > 1 +) +SELECT + s.*, + t.related_data +FROM standard_cte s +JOIN another_table t ON t.id = s.column1 +ORDER BY s.record_count DESC, s.last_update DESC +SQL;` diff --git a/src/services/tree-sitter/__tests__/fixtures/sample-python.ts b/src/services/tree-sitter/__tests__/fixtures/sample-python.ts new file mode 100644 index 00000000000..b3416999a5c --- /dev/null +++ b/src/services/tree-sitter/__tests__/fixtures/sample-python.ts @@ -0,0 +1,150 @@ +export const samplePythonContent = ` +# NOTE: Some Python constructs are inherently single-line and exempt from the 4-line requirement: +# - Simple import statements +# - Global/nonlocal declarations +# - Simple variable declarations + +# Class definition with decorators - demonstrates decorated class structure +@class_decorator_one +@class_decorator_two +class MultiLineDecoratedClass: + """ + Class demonstrating multi-line structure with decorators + and docstring spanning multiple lines for clarity + """ + def __init__(self, value: int): + self.value = value + +# Method definition - demonstrates class method structure +class MethodContainer: + """Class containing method definitions""" + + def multi_line_method( + self, + param1: str, + param2: int, + param3: list[str] + ) -> str: + """Method with multiple parameters and return type""" + result = self._process(param1, param2) + return f"{result}: {param3}" + +# Async function with type annotations and decorators +@function_decorator_one +@function_decorator_two +async def multi_line_async_function( + param1: str, + param2: int, + param3: list[str] +) -> None: + """Async function demonstrating multiple decorators and type hints""" + await async_operation_one(param1) + result = await async_operation_two(param2) + return await async_operation_three(result, param3) + +# Generator function demonstrating yield +def multi_line_generator( + start: int, + end: int, + step: int = 1 +) -> int: + """Generator function demonstrating yield across multiple lines""" + current = start + while current < end: + yield current + current += step + +# Lambda with multiple lines using parentheses +multi_line_lambda = ( + lambda x, y, z: + x * y + z + if x > 0 + else z +) + +# List comprehension across multiple lines +multi_line_comprehension = [ + x * y + z + for x in range(10) + for y in range(5) + for z in range(3) + if x % 2 == 0 and y % 2 == 0 +] + +# Complex with statement demonstrating context management +with ( + open('file1.txt', 'r', encoding='utf-8') as f1, + open('file2.txt', 'r', encoding='utf-8') as f2, + open('file3.txt', 'r', encoding='utf-8') as f3 +): + content1 = f1.read().strip() + content2 = f2.read().strip() + content3 = f3.read().strip() + +# Try statement with multiple except blocks +try: + result = complex_operation_one() + intermediate = complex_operation_two(result) + final = complex_operation_three(intermediate) +except ValueError as value_error: + handle_value_error(value_error) + log_error("ValueError occurred", value_error) +except TypeError as type_error: + handle_type_error(type_error) + log_error("TypeError occurred", type_error) +finally: + cleanup_operations() + log_completion() + +# Multi-line import statement (4+ lines) +from typing import ( + List, + Dict, + Optional, + Union, + TypeVar +) + +# Global and nonlocal statements (exempt from 4-line requirement) +def scope_demonstration(): + global global_var_one + global global_var_two, global_var_three + def inner_function(): + nonlocal outer_var_one + nonlocal outer_var_two, outer_var_three + outer_var_one = 1 + +# Match case statement (Python 3.10+) +def multi_line_pattern_match(value: dict): + match value: + case { + "type": "user", + "name": str() as name, + "age": int() as age + }: + handle_user(name, age) + case { + "type": "group", + "members": list() as members, + "admin": str() as admin + }: + handle_group(members, admin) + case _: + handle_default() + +# Complex type annotations +ComplexType = TypeVar('ComplexType') +multi_line_type_annotation: dict[ + str, + Union[ + List[int], + Dict[str, bool], + Optional[ComplexType] + ] +] = {} +` + +export default { + path: "test.py", + content: samplePythonContent, +} diff --git a/src/services/tree-sitter/__tests__/fixtures/sample-ruby.ts b/src/services/tree-sitter/__tests__/fixtures/sample-ruby.ts new file mode 100644 index 00000000000..1c42e978eec --- /dev/null +++ b/src/services/tree-sitter/__tests__/fixtures/sample-ruby.ts @@ -0,0 +1,577 @@ +export default String.raw` +# Standard class definition test - at least 4 lines +class StandardClassDefinition + # Class-level constant with descriptive initialization + STANDARD_CONFIG = { + name: "StandardClass", + version: "1.0.0", + description: "Test standard class definition", + features: ["basic", "advanced", "expert"] + }.freeze + + # Instance method to demonstrate class functionality + def standard_instance_method + initialize_configuration + validate_settings + process_features + generate_output + end + + # Class method to demonstrate singleton method definition + def self.standard_class_method + validate_environment + initialize_resources + configure_system + cleanup_resources + end + + # Nested class definition test + class NestedClassDefinition + def nested_instance_method + setup_nested_environment + process_nested_data + validate_nested_results + cleanup_nested_resources + end + end +end + +# Method definition variations test +class MethodDefinitionTypes + # Standard instance method test + def standard_instance_method(data, format: :json) + validate_input(data) + process_data(data) + format_output(format) + generate_response + end + + # Class method test + def self.class_method_example(config) + validate_config(config) + initialize_system(config) + process_configuration(config) + finalize_setup(config) + end + + # Singleton method test + class << self + def singleton_method_example + setup_singleton_context + process_singleton_data + validate_singleton_result + cleanup_singleton_resources + end + end + + # Method with rescue and ensure test + def exception_handling_method + setup_resources + process_operation + validate_results + rescue StandardError => e + log_error(e) + notify_admin(e) + handle_failure(e) + ensure + cleanup_resources + reset_state + update_metrics + log_completion + end + + # Method alias test + def original_method_name + initialize_process + perform_operation + validate_results + generate_output + end + alias_method :aliased_method_name, :original_method_name +end + +# Module definition test - demonstrating standard and nested modules +module StandardModuleDefinition + def self.module_class_method + initialize_module_context + setup_module_resources + process_module_data + cleanup_module_resources + end + + def standard_module_method + validate_module_input + process_module_operation + generate_module_output + finalize_module_task + end + + # Nested module test + module NestedModuleDefinition + def self.nested_module_method + setup_nested_context + initialize_nested_resources + process_nested_data + cleanup_nested_state + end + end +end + +# Module with nested components test +module ModuleWithComponents + # Class methods module test + module ClassMethods + def class_level_operation + validate_class_context + initialize_class_resources + process_class_data + cleanup_class_state + end + end + + # Instance methods module test + module InstanceMethods + def instance_level_operation + setup_instance_context + process_instance_data + validate_instance_result + cleanup_instance_state + end + end + + # Module inclusion hook test + def self.included(base) + base.extend(ClassMethods) + base.include(InstanceMethods) + base.class_eval do + setup_inclusion_hooks + initialize_module_state + register_callbacks + finalize_setup + end + end +end + +# Mixin patterns test - demonstrating include, extend, and prepend +module MixinTestModule + def mixin_operation + setup_mixin_context + process_mixin_data + validate_mixin_result + cleanup_mixin_state + end +end + +# Class demonstrating mixin usage +# Mixin test module with comprehensive functionality +module MixinTestModule + def shared_mixin_method + setup_mixin_context + process_mixin_data + validate_mixin_result + finalize_mixin_operation + end +end + +# Class demonstrating mixin usage - at least 4 lines per mixin type +class MixinImplementation + # Include test with method implementation + include MixinTestModule + def included_method + setup_included_context + process_included_data + validate_included_result + finalize_included_operation + end + + # Extend test with class method implementation + extend MixinTestModule + class << self + def extended_method + setup_extended_context + process_extended_data + validate_extended_result + finalize_extended_operation + end + end + + # Prepend test with method implementation + prepend MixinTestModule + def prepended_method + setup_prepended_context + process_prepended_data + validate_prepended_result + finalize_prepended_operation + end +end + +# Block syntax test - demonstrating do/end and brace blocks +class BlockSyntaxExamples + # Block with do/end syntax test + def method_with_do_end_block + result = [1, 2, 3, 4].map do |number| + validate_number(number) + process_number(number) + transform_number(number) + format_number(number) + end + end + + # Block with brace syntax test + def method_with_brace_block + result = [1, 2, 3, 4].select { |number| + validate_number(number) + check_conditions(number) + verify_constraints(number) + meets_criteria?(number) + } + end + + # Lambda definition test + STANDARD_LAMBDA = lambda { |input| + validate_lambda_input(input) + process_lambda_data(input) + transform_lambda_result(input) + format_lambda_output(input) + } + + # Proc definition test + STANDARD_PROC = Proc.new do |data| + setup_proc_context(data) + validate_proc_input(data) + process_proc_data(data) + finalize_proc_result(data) + end +end + +# Attribute accessor test +class AttributeAccessorExamples + # Reader attributes test + attr_reader :standard_reader, + :computed_reader, + :cached_reader, + :formatted_reader + + # Writer attributes test + attr_writer :standard_writer, + :validated_writer, + :normalized_writer, + :formatted_writer + + # Full accessor attributes test + attr_accessor :standard_accessor, + :validated_accessor, + :normalized_accessor, + :formatted_accessor + + def initialize + initialize_readers + initialize_writers + initialize_accessors + validate_attributes + end + + private + + def initialize_readers + @standard_reader = "Standard Read Value" + @computed_reader = calculate_reader_value + @cached_reader = fetch_cached_value + @formatted_reader = format_reader_value + end +end + +# Pattern matching test +class PatternMatchingExamples + # Case/in pattern matching test + def process_data_pattern(input) + case input + in { type: "record", id: Integer => record_id, data: { name: String => name } } + process_record_match(record_id) + validate_record_data(name) + transform_record_result + finalize_record_processing + in { type: "collection", items: Array => items } if items.size > 0 + process_collection_match(items) + validate_collection_items + transform_collection_data + finalize_collection_result + else + handle_unknown_pattern + log_pattern_error + generate_error_result + track_pattern_failure + end + end + +# Rails-style class macro test +class RailsStyleMacroExample < ApplicationRecord + # Association macros test + has_many :test_children, + class_name: 'TestChild', + foreign_key: 'parent_id', + dependent: :destroy + + belongs_to :test_parent, + class_name: 'TestParent', + foreign_key: 'parent_id', + optional: true + + # Validation macros test + validates :test_field, + presence: true, + uniqueness: { case_sensitive: false }, + format: { with: /\A[A-Z0-9_]+\z/ } + + # Callback macros test + before_validation :normalize_test_data, + :validate_test_rules, + :check_test_state, + :ensure_test_valid +end + +# Exception handling test +class ExceptionHandlingExample + # Begin/rescue/ensure block test + def exception_handling_method + begin + setup_test_resources + perform_test_operation + validate_test_result + generate_test_output + rescue TestError => e + handle_test_error(e) + log_test_failure(e) + notify_test_admin(e) + track_test_error(e) + rescue StandardError => e + handle_standard_error(e) + log_standard_failure(e) + notify_system_admin(e) + track_system_error(e) + ensure + cleanup_test_resources + reset_test_state + update_test_metrics + log_test_completion + end + end +end + +# Hash and symbol definition test +class HashAndSymbolExamples + # Hash syntax variations test + HASH_EXAMPLES = { + symbol_key: 'symbol_value', + 'string_key' => 'string_value', + :old_symbol_key => 'old_style_value', + nested_hash: { + key1: 'value1', + key2: 'value2' + } + } + + # Symbol definition variations test + SYMBOL_EXAMPLES = [ + :standard_symbol, + :'quoted_symbol', + :"interpolated_#{type}_symbol", + '%s{non_alphanumeric:symbol}'.to_sym + ] + + # String interpolation test + def string_interpolation_example(status) + timestamp = Time.now.strftime('%Y-%m-%d %H:%M:%S') + <<~MESSAGE + Test Status [#{timestamp}] + Current State: #{status.upcase} + Details: #{fetch_details} + Metrics: #{calculate_metrics} + MESSAGE + end +end + +# REGULAR EXPRESSIONS - testing pattern matching +class RegexImplementation + # Email validation pattern + EMAIL_PATTERN = %r{ + \A + [a-zA-Z0-9._%+-]+ # username + @ + [a-zA-Z0-9.-]+ # domain name + \.[a-zA-Z]{2,} # domain extension + \z + }x + + # URL validation pattern + URL_PATTERN = %r{ + \A + https?:// # protocol + (?:[\w-]+\.)+ # subdomains + [\w-]+ # domain + (?:/[\w- ./?%&=]*)? # path and query + \z + }x + + def validate_patterns(input) + case input + when EMAIL_PATTERN + process_email_match(input) + validate_email_parts(input) + check_email_availability + register_email_validation + when URL_PATTERN + process_url_match(input) + validate_url_components(input) + check_url_accessibility + register_url_validation + end + end +end + +# ATTRIBUTE ACCESSORS - testing comprehensive accessor patterns +class ModelAttributeImplementation + # Reader attributes with validation + attr_reader :validated_reader_attribute, + :computed_reader_attribute, + :cached_reader_attribute, + :formatted_reader_attribute + + # Writer attributes with preprocessing + attr_writer :validated_writer_attribute, + :normalized_writer_attribute, + :encrypted_writer_attribute, + :formatted_writer_attribute + + # Full accessors with complex logic + attr_accessor :managed_accessor_attribute, + :versioned_accessor_attribute, + :tracked_accessor_attribute, + :cached_accessor_attribute + + def initialize(config) + initialize_reader_attributes(config) + initialize_writer_attributes(config) + initialize_accessor_attributes(config) + validate_all_attributes + end + + private + + def initialize_reader_attributes(config) + @validated_reader_attribute = validate_reader_input(config[:reader]) + @computed_reader_attribute = compute_reader_value(config[:compute]) + @cached_reader_attribute = cache_reader_value(config[:cache]) + @formatted_reader_attribute = format_reader_value(config[:format]) + end +end + +# CLASS MACROS - testing Rails-style macro implementations +class RailsModelImplementation < ApplicationRecord + # Association macros with complex options + has_many :managed_children, + class_name: 'ManagedChild', + foreign_key: 'parent_identifier', + dependent: :destroy, + counter_cache: true + + belongs_to :managed_parent, + class_name: 'ManagedParent', + foreign_key: 'parent_identifier', + touch: true, + optional: true + + # Validation macros with custom rules + validates :identifier_field, + presence: true, + uniqueness: { case_sensitive: false }, + format: { with: /\A[A-Z0-9_]+\z/ }, + length: { minimum: 8, maximum: 32 } + + # Callback macros with complex logic + before_validation :normalize_identifier, + :validate_business_rules, + :check_dependencies, + :ensure_valid_state + + # Scope macros with complex queries + scope :active_records, -> { + where(active: true) + .where.not(deleted_at: nil) + .order(created_at: :desc) + .includes(:managed_children) + } +end + +# EXCEPTION HANDLING - testing comprehensive error management +class ErrorHandlingImplementation + class BusinessLogicError < StandardError; end + class ValidationError < StandardError; end + class ProcessingError < StandardError; end + + def process_with_error_handling(data) + begin + validate_input_data(data) + process_validated_data(data) + handle_successful_processing + generate_success_response + rescue BusinessLogicError => e + handle_business_error(e) + notify_business_stakeholders(e) + log_business_failure(e) + raise + rescue ValidationError => e + handle_validation_error(e) + notify_system_admins(e) + log_validation_failure(e) + retry if should_retry? + rescue ProcessingError => e + handle_processing_error(e) + attempt_error_recovery(e) + notify_error_handlers(e) + raise if critical_error?(e) + ensure + cleanup_resources + reset_processing_state + update_processing_metrics + log_processing_completion + end + end +end + +# METAPROGRAMMING - testing dynamic method generation +class MetaprogrammingImplementation + # Dynamic method definition with validation + [:create, :update, :delete, :archive].each do |operation| + define_method("validate_#{operation}") do |record| + validate_permissions(operation, record) + validate_business_rules(operation, record) + validate_constraints(operation, record) + log_validation_attempt(operation, record) + end + + define_method("process_#{operation}") do |record| + validate_operation = send("validate_#{operation}", record) + process_operation(operation, record) + notify_observers(operation, record) + log_operation_completion(operation, record) + end + end + + # Method missing implementation with logging + def method_missing(method_name, *args, &block) + if method_name.to_s.start_with?('find_by_') + attribute = method_name.to_s.sub('find_by_', '') + log_dynamic_finder(attribute, args) + find_record_by_attribute(attribute, args.first) + else + log_unknown_method(method_name, args) + super + end + end + + def respond_to_missing?(method_name, include_private = false) + method_name.to_s.start_with?('find_by_') || super + end +end +` diff --git a/src/services/tree-sitter/__tests__/fixtures/sample-rust.ts b/src/services/tree-sitter/__tests__/fixtures/sample-rust.ts new file mode 100644 index 00000000000..9b37462b36f --- /dev/null +++ b/src/services/tree-sitter/__tests__/fixtures/sample-rust.ts @@ -0,0 +1,308 @@ +export default String.raw` +// Function definition tests - standard, async, and const functions +fn test_function_definition( + param1: i32, + param2: &str, + param3: Option, + param4: Vec +) -> Result { + println!("Function definition test"); + let result = param1 + param3.map_or(0, |s| s.len() as i32); + Ok(result) +} + +async fn test_async_function_definition( + url: &str, + timeout: std::time::Duration, + retry_count: u32, + headers: Vec<(&str, &str)> +) -> Result> { + println!("Async function test"); + println!("URL: {}, timeout: {:?}, retries: {}", url, timeout, retry_count); + Ok(String::from("Async test response")) +} + +const fn test_const_function_definition( + value: T, + multiplier: usize, + prefix: &'static str, + suffix: &'static str +) -> [T; 4] { + println!("Const function test"); + [value; 4] +} + +// Struct definition tests - standard, tuple, and unit structs +// Note: Unit structs are exempt from 4-line requirement due to language syntax +struct test_struct_definition { + name: String, + value: i32, + data: Option>, + metadata: std::collections::HashMap, + created_at: std::time::SystemTime, +} + +struct test_tuple_struct_definition( + String, + i32, + Option>, + std::collections::HashMap, + std::time::SystemTime +); + +// Unit struct - exempt from 4-line requirement +struct test_unit_struct_definition; + +// Enum definition tests +enum test_enum_definition { + // Unit variant - exempt from 4-line requirement + TestUnitVariant, + + // Tuple variant with multiple fields + TestTupleVariant( + String, + i32, + f64, + Vec + ), + + // Struct variant with fields + TestStructVariant { + name: String, + value: i32, + data: Option>, + timestamp: std::time::SystemTime + }, + + // Recursive variant + TestRecursiveVariant( + String, + Box + ) +} + +// Trait definition test +trait test_trait_definition { + // Required method + fn test_required_method( + &self, + input: &str, + count: usize + ) -> Result>; + + // Method with generics + fn test_generic_method( + &self, + data: T, + prefix: &str + ) -> Option; + + // Default implementation + fn test_default_method( + &self, + message: &str + ) -> String { + format!("Default implementation: {}", message) + } +} + +// Implementation test +impl test_struct_definition { + fn test_implementation_method( + &self, + multiplier: i32, + offset: i32, + scale_factor: f64 + ) -> i32 { + (self.value * multiplier + offset) as i32 + } + + fn test_static_method( + name: String, + value: i32, + metadata: std::collections::HashMap + ) -> Self { + Self { + name, + value, + data: None, + metadata, + created_at: std::time::SystemTime::now(), + } + } +} + +// Trait implementation test +impl test_trait_definition for test_struct_definition { + fn test_required_method( + &self, + input: &str, + count: usize + ) -> Result> { + Ok(format!("{}: {}", self.name, input.repeat(count))) + } + + fn test_generic_method( + &self, + data: T, + prefix: &str + ) -> Option { + if self.value > 0 { + Some(data) + } else { + None + } + } +} + +// Module definition test +mod test_module_definition { + use std::collections::HashMap; + use std::io::{self, Read, Write}; + use std::time::{Duration, SystemTime}; + use super::{ + test_struct_definition, + test_trait_definition, + test_enum_definition + }; + + pub fn test_module_function( + param: &test_struct_definition, + timeout: Duration, + retry_count: u32 + ) -> io::Result { + Ok(format!("Module test: {}", param.name)) + } +} + +// Macro definition tests +macro_rules! test_macro_definition { + // Basic pattern + ($test_expr:expr) => { + println!("Test macro: {}", $test_expr) + }; + + // Complex pattern with repetition + ($test_expr:expr, $($test_arg:expr),+ $(,)?) => { + { + print!("Test macro: {}", $test_expr); + $( + print!(", argument: {}", $test_arg); + )+ + println!(); + } + }; + + // Pattern with different types + ($test_expr:expr, $test_ident:ident, $test_ty:ty) => { + { + let $test_ident: $test_ty = $test_expr; + println!("Test macro with type: {}", stringify!($test_ty)); + } + }; +} + +// Procedural macro test - shows typical usage +#[derive( + Debug, + Clone, + PartialEq, + test_procedural_macro_definition, + serde::Serialize, + serde::Deserialize +)] +struct test_proc_macro_struct { + test_field1: String, + test_field2: i32, + test_field3: Option>, + test_field4: std::time::SystemTime, +} + +// Type alias tests - Note: Simple type aliases are exempt from 4-line requirement +type test_type_alias = fn(i32, &str) -> Result; + +// Complex generic type alias +type test_generic_type_alias = Result< + std::collections::HashMap>, + Box +> where T: Clone + Send + 'static, E: std::error::Error + 'static; + +// Const and static tests +const TEST_CONSTANT_DEFINITION: f64 = + 3.141592653589793238462643383279502884197169399375105820974944592307816406286; + +static TEST_STATIC_DEFINITION: &str = + "This is a test static string\n\ + that spans multiple lines\n\ + to meet the four-line requirement\n\ + for proper testing purposes"; + +// Lifetime parameter tests +struct test_lifetime_definition<'short, 'long: 'short> { + test_ref1: &'short str, + test_ref2: &'long str, + test_ref3: &'short [&'long str], + test_ref4: std::collections::HashMap<&'short str, &'long str>, + test_ref5: Box, +} + +impl<'short, 'long: 'short> test_lifetime_definition<'short, 'long> { + fn test_lifetime_method<'a, 'b>( + &'a self, + input: &'b str, + data: &'short [&'long str] + ) -> &'short str + where + 'b: 'a, + 'short: 'b, + { + self.test_ref1 + } +} + +// Additional test structures +// Unsafe block test +impl test_struct_definition { + unsafe fn test_unsafe_function( + ptr: *const i32, + len: usize, + offset: isize + ) -> Option { + if ptr.is_null() { + return None; + } + Some(*ptr.offset(offset)) + } +} + +// Where clause test +fn test_where_clause_function( + t: T, + u: U, + v: V +) -> Result> +where + T: Clone + std::fmt::Debug, + U: AsRef + 'static, + V: Into + Send, +{ + println!("Testing where clause: {:?}", t); + Ok(t) +} + +// Pattern matching test +fn test_match_expression( + value: test_enum_definition +) -> String { + match value { + test_enum_definition::TestUnitVariant => + "Unit variant".to_string(), + test_enum_definition::TestTupleVariant(s, i, f, v) => + format!("Tuple: {}, {}, {}, {:?}", s, i, f, v), + test_enum_definition::TestStructVariant { name, value, data, timestamp } => + format!("Struct: {}, {}, {:?}, {:?}", name, value, data, timestamp), + test_enum_definition::TestRecursiveVariant(_, _) => + "Recursive variant".to_string(), + } +} +` diff --git a/src/services/tree-sitter/__tests__/fixtures/sample-scala.ts b/src/services/tree-sitter/__tests__/fixtures/sample-scala.ts new file mode 100644 index 00000000000..df93dfd930c --- /dev/null +++ b/src/services/tree-sitter/__tests__/fixtures/sample-scala.ts @@ -0,0 +1,94 @@ +export const sampleScala = ` +package com.example.test + +import scala.collection.mutable +import scala.concurrent.Future + +// Regular class with type parameters +class Container[A, B](val first: A, val second: B) { + def swap: Container[B, A] = new Container(second, first) +} + +// Case class with type parameters +case class TestCaseClass[A, B]( + field1: A, + field2: B, + field3: List[A] +)(implicit ctx: Context) + +// Abstract class +abstract class AbstractBase { + def abstractMethod: String + val abstractValue: Int +} + +// Trait with abstract type member +trait TestTrait { + type T + def method[A]( + param1: A, + param2: List[T] + ): Option[A] +} + +// Object companion +object TestTrait { + def apply[T](value: T): TestTrait = ??? +} + +// Case object +case object SingletonValue extends AbstractBase { + def abstractMethod: String = "implemented" + val abstractValue: Int = 42 +} + +// Class with pattern matching +class PatternMatcher { + def testMatch(value: Any): Int = value match { + case s: String => + s.length + case n: Int if n > 0 => + n * 2 + case _ => + 0 + } +} + +// Implicit class for extension methods +implicit class RichString(val str: String) { + def truncate(maxLength: Int): String = + if (str.length <= maxLength) str + else str.take(maxLength) + "..." +} + +// Type alias and lazy val +object Types { + type StringMap[T] = Map[String, T] + + lazy val heavyComputation: Int = { + Thread.sleep(1000) + 42 + } +} + +// For comprehension example +class ForComprehension { + def processItems(items: List[Int]): List[Int] = { + for { + item <- items + if item > 0 + doubled = item * 2 + if doubled < 100 + } yield doubled + } +} + +// Var and val definitions +object Variables { + val immutableValue: Int = 42 + var mutableValue: String = "changeable" + + private lazy val lazyValue: Double = { + math.random() + } +}` diff --git a/src/services/tree-sitter/__tests__/fixtures/sample-solidity.ts b/src/services/tree-sitter/__tests__/fixtures/sample-solidity.ts new file mode 100644 index 00000000000..ac4a42f7cee --- /dev/null +++ b/src/services/tree-sitter/__tests__/fixtures/sample-solidity.ts @@ -0,0 +1,102 @@ +export const sampleSolidity = ` +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface ITestInterface { + function interfaceFunction(uint256 value) external returns (bool); + event InterfaceEvent(address indexed sender, uint256 value); + error InterfaceError(string message); +} + +library MathLib { + function add(uint256 a, uint256 b) internal pure returns (uint256) { + return a + b; + } + + function subtract(uint256 a, uint256 b) internal pure returns (uint256) { + require(b <= a, "Underflow"); + return a - b; + } +} + +contract TestContract is ITestInterface { + using MathLib for uint256; + + struct UserInfo { + address userAddress; + uint256 balance; + mapping(bytes32 => bool) permissions; + uint256 lastUpdate; + } + + enum UserRole { + None, + Basic, + Admin, + SuperAdmin + } + + uint256 private immutable totalSupply; + mapping(address => UserInfo) private users; + UserRole[] private roles; + + event Transfer( + address indexed from, + address indexed to, + uint256 amount + ); + + error InsufficientBalance( + address user, + uint256 available, + uint256 required + ); + + modifier onlyAdmin() { + require( + users[msg.sender].permissions["ADMIN_ROLE"], + "Admin only" + ); + _; + } + + constructor(uint256 _initialSupply) { + totalSupply = _initialSupply; + users[msg.sender].userAddress = msg.sender; + users[msg.sender].balance = _initialSupply; + users[msg.sender].permissions["ADMIN_ROLE"] = true; + } + + function transfer( + address to, + uint256 amount + ) external returns (bool) { + if (users[msg.sender].balance < amount) { + revert InsufficientBalance({ + user: msg.sender, + available: users[msg.sender].balance, + required: amount + }); + } + + users[msg.sender].balance = users[msg.sender].balance.subtract(amount); + users[to].balance = users[to].balance.add(amount); + + emit Transfer(msg.sender, to, amount); + return true; + } + + function interfaceFunction( + uint256 value + ) external override returns (bool) { + return value > 0; + } + + fallback() external payable { + revert("Fallback not allowed"); + } + + receive() external payable { + revert("Direct deposits not allowed"); + } +}` diff --git a/src/services/tree-sitter/__tests__/fixtures/sample-swift.ts b/src/services/tree-sitter/__tests__/fixtures/sample-swift.ts new file mode 100644 index 00000000000..5dea06402c4 --- /dev/null +++ b/src/services/tree-sitter/__tests__/fixtures/sample-swift.ts @@ -0,0 +1,298 @@ +export default String.raw` +// MARK: - Class Definitions + +// Standard class definition test - at least 4 lines long +class StandardClassDefinition { + private var standardProperty: String + + func standardMethod() -> String { + return "Standard class method" + } +} + +// Final class definition test - at least 4 lines long +final class FinalClassDefinition { + private let finalProperty: Int + + func finalClassMethod( + parameter: String + ) -> Int { + return finalProperty + } +} + +// Open class definition test - at least 4 lines long +open class OpenClassDefinition { + public var openProperty: Double + + open func openOverridableMethod( + parameter1: String, + parameter2: Int + ) -> Double { + return openProperty + } +} + +// Class with inheritance and protocol conformance test - at least 4 lines long +class InheritingClassDefinition: StandardClassDefinition, ProtocolDefinition { + var protocolRequiredProperty: String = "Required property" + + override func standardMethod() -> String { + return "Overridden method" + } + + func protocolRequiredMethod( + with parameter: String + ) -> Bool { + return !parameter.isEmpty + } +} + +// MARK: - Struct Definitions + +// Standard struct definition test - at least 4 lines long +struct StandardStructDefinition { + private var standardStructProperty: String + let readOnlyProperty: Int + + mutating func modifyingMethod( + newValue: String + ) { + standardStructProperty = newValue + } +} + +// Generic struct definition test - at least 4 lines long +struct GenericStructDefinition { + private var items: [T] + private var mappings: [T: U] + + init( + items: [T] = [], + mappings: [T: U] = [:] + ) { + self.items = items + self.mappings = mappings + } + + func findMapping(for key: T) -> U? { + return mappings[key] + } +} + +// MARK: - Protocol Definitions + +// Protocol with requirements test - at least 4 lines long +protocol ProtocolDefinition { + var protocolRequiredProperty: String { get set } + + func protocolRequiredMethod( + with parameter: String + ) -> Bool +} + +// Protocol with associated type test - at least 4 lines long +protocol AssociatedTypeProtocolDefinition { + associatedtype AssociatedItem + + var items: [AssociatedItem] { get set } + + func add( + item: AssociatedItem + ) + + func remove(at index: Int) +} + +// MARK: - Extension Definitions + +// Class extension test - at least 4 lines long +extension StandardClassDefinition { + func classExtensionMethod( + parameter1: String, + parameter2: Int + ) -> String { + return "Extended class method: \\(parameter1), \\(parameter2)" + } +} + +// Struct extension test - at least 4 lines long +extension StandardStructDefinition { + func structExtensionMethod( + parameter: Double + ) -> String { + return "Extended struct method: \\(parameter)" + } +} + +// Protocol extension test - at least 4 lines long +extension ProtocolDefinition { + func protocolExtensionMethod( + parameter1: Int, + parameter2: Bool + ) -> String { + return "Protocol extension method" + } +} + +// MARK: - Function Definitions + +// Instance method definition test - at least 4 lines long +class MethodContainer { + func instanceMethodDefinition( + parameter1: String, + parameter2: Int, + parameter3: Double + ) -> String { + return "Instance method" + } +} + +// Type method definition test - at least 4 lines long +struct TypeMethodContainer { + static func typeMethodDefinition( + parameter1: String, + parameter2: Int, + parameter3: Double + ) -> String { + return "Type method" + } +} + +// MARK: - Property Definitions + +// Stored property definition test - at least 4 lines long +class StoredPropertyContainer { + // Simple stored property + private var privateStoredProperty: String = "Private" + + // Stored property with property observer + var storedPropertyWithObserver: Int = 0 { + willSet { + print("Will change from \\(storedPropertyWithObserver) to \\(newValue)") + } + didSet { + print("Did change from \\(oldValue) to \\(storedPropertyWithObserver)") + } + } +} + +// Computed property definition test - at least 4 lines long +class ComputedPropertyContainer { + private var backingStorage: String = "" + + // Full computed property + var computedProperty: String { + get { + return backingStorage.uppercased() + } + set { + backingStorage = newValue.lowercased() + } + } + + // Read-only computed property + var readOnlyComputedProperty: Int { + return backingStorage.count * 2 + } +} + +// MARK: - Initializer Definitions + +// Designated initializer definition test - at least 4 lines long +class DesignatedInitializerContainer { + let property1: String + let property2: Int + + // Designated initializer + init( + property1: String, + property2: Int + ) { + self.property1 = property1 + self.property2 = property2 + } +} + +// Convenience initializer definition test - at least 4 lines long +class ConvenienceInitializerContainer { + let property1: String + let property2: Int + + // Designated initializer + init(property1: String, property2: Int) { + self.property1 = property1 + self.property2 = property2 + } + + // Convenience initializer + convenience init( + defaultsWithOverride: String = "Default" + ) { + self.init( + property1: defaultsWithOverride, + property2: 42 + ) + } +} + +// MARK: - Deinitializer Definition + +// Deinitializer definition test - at least 4 lines long +class DeinitializerDefinition { + private var resource: String + + init(resource: String) { + self.resource = resource + print("Initialized with: \\(resource)") + } + + deinit { + print("Releasing resource: \\(resource)") + resource = "" + // Perform cleanup + } +} + +// MARK: - Subscript Definition + +// Subscript definition test - at least 4 lines long +class SubscriptDefinition { + private var items: [String] = [] + + subscript( + index: Int, + default defaultValue: String = "" + ) -> String { + get { + guard index >= 0 && index < items.count else { + return defaultValue + } + return items[index] + } + set { + while items.count <= index { + items.append(defaultValue) + } + items[index] = newValue + } + } +} + +// MARK: - Type Alias Definition + +// Type alias definition test - at least 4 lines long +class TypeAliasContainer { + // Simple type alias + typealias SimpleTypeAlias = String + + // Complex type alias with generic constraints + typealias DictionaryOfArrays< + Key: Hashable, + Value: Equatable + > = [Key: [Value]] + + // Using the type alias + var dictionaryOfArrays: DictionaryOfArrays = [:] +} +` diff --git a/src/services/tree-sitter/__tests__/fixtures/sample-systemrdl.ts b/src/services/tree-sitter/__tests__/fixtures/sample-systemrdl.ts new file mode 100644 index 00000000000..a490396e9cb --- /dev/null +++ b/src/services/tree-sitter/__tests__/fixtures/sample-systemrdl.ts @@ -0,0 +1,86 @@ +export default String.raw` +// Component definition test - showing register block +addrmap top_map { + name = "Top Level Address Map"; + desc = "Example SystemRDL address map"; + + reg block_ctrl { + name = "Block Control Register"; + desc = "Control register for the block"; + + field { + name = "Enable"; + desc = "Block enable bit"; + sw = rw; + hw = r; + } enable[1:0]; + + field { + name = "Status"; + desc = "Block status"; + sw = r; + hw = w; + } status; + }; +}; + +// Field definition test with properties +reg status_reg { + field { + name = "Error Flags"; + sw = rw; + hw = w; + reset = 0x0; + + enum error_types { + NO_ERROR = 0; + TIMEOUT = 1; + OVERFLOW = 2; + UNDERFLOW = 3; + }; + } errors[3:0]; +}; + +// Property definition test +property my_custom_prop { + type = string; + component = reg; + default = "undefined"; +}; + +// Parameter definition test +parameter DATA_WIDTH { + type = longint unsigned; + default = 32; +}; + +// Enum definition test +enum interrupt_type { + LEVEL = 0 { desc = "Level-triggered interrupt"; }; + EDGE = 1 { desc = "Edge-triggered interrupt"; }; +}; + +// Complex register with multiple fields +reg complex_reg { + name = "Complex Register"; + desc = "Register with multiple fields"; + + field { + name = "Control"; + sw = rw; + hw = r; + } ctrl[7:0]; + + field { + name = "Status"; + sw = r; + hw = w; + } status[15:8]; + + field { + name = "Flags"; + sw = rw1c; + hw = w; + } flags[23:16]; +}; +` diff --git a/src/services/tree-sitter/__tests__/fixtures/sample-tlaplus.ts b/src/services/tree-sitter/__tests__/fixtures/sample-tlaplus.ts new file mode 100644 index 00000000000..a976fa83ad5 --- /dev/null +++ b/src/services/tree-sitter/__tests__/fixtures/sample-tlaplus.ts @@ -0,0 +1,49 @@ +export default String.raw` +---- MODULE SimpleModule ---- +EXTENDS Naturals, Sequences + +CONSTANT N +VARIABLE x, y, z + +\* Simple operator definition +Max(a, b) == + IF a > b THEN a + ELSE b + +\* Multi-line operator +ComplexOperator(seq) == + LET sum == + CHOOSE s \in Nat : + \E i \in 1..Len(seq) : + s = Sum(SubSeq(seq, 1, i)) + IN sum + +\* Function definition +SimpleFunction[a \in 1..N] == + LET square == a * a + IN square + 1 + +\* Procedure-style definition +ProcessStep == + /\ x' = Max(x, y) + /\ y' = Min(x, y) + /\ z' = x + y + +\* Variable declaration with complex init +vars == <> + +\* Complex operator with multiple cases +HandleCase(val) == + CASE val = 1 -> "one" + [] val = 2 -> "two" + [] val = 3 -> "three" + [] OTHER -> "unknown" + +\* Recursive operator definition +Factorial[n \in Nat] == + IF n = 0 + THEN 1 + ELSE n * Factorial[n-1] + +==== +` diff --git a/src/services/tree-sitter/__tests__/fixtures/sample-toml.ts b/src/services/tree-sitter/__tests__/fixtures/sample-toml.ts new file mode 100644 index 00000000000..9b4ba1036b9 --- /dev/null +++ b/src/services/tree-sitter/__tests__/fixtures/sample-toml.ts @@ -0,0 +1,72 @@ +export const sampleToml = `# This is a TOML document with various structures + +# Simple table +[database] +server = "192.168.1.1" +ports = [ 8001, 8001, 8002 ] +connection_max = 5000 +enabled = true + +# Table with inline table +[servers] +alpha = { ip = "10.0.0.1", role = "frontend" } +beta = { ip = "10.0.0.2", role = "backend" } + +# Nested tables +[owner.personal] +name = "Tom Preston-Werner" +dob = 1979-05-27T07:32:00-08:00 + +# Array of tables +[[products]] +name = "Hammer" +sku = 738594937 +color = "red" + +[[products]] # Array of tables +name = "Nail" +sku = 284758393 +color = "gray" + +# Complex types +[complex_values] +strings = [ + "basic string", + ''' + multi-line + basic string + ''', + 'literal string', + """ + multi-line + literal string + """ +] +numbers = [ 42, -17, 3.14, 1e10 ] +dates = [ + 1979-05-27T07:32:00-08:00, + 1979-05-27, + 07:32:00 +] + +# Dotted keys +"dotted.key.example" = "value" +physical.color = "orange" +physical.shape = "round" + +# Mixed content table +[mixed_content] +title = "Mixed Content Example" +description = """ +A table containing various TOML +data types and structures for +testing purposes +""" +features = [ + "tables", + "arrays", + "strings", + "numbers" +] +metadata = { created = 2024-01-01, updated = 2024-04-13 } +` diff --git a/src/services/tree-sitter/__tests__/fixtures/sample-tsx.ts b/src/services/tree-sitter/__tests__/fixtures/sample-tsx.ts new file mode 100644 index 00000000000..2a9149d7a6b --- /dev/null +++ b/src/services/tree-sitter/__tests__/fixtures/sample-tsx.ts @@ -0,0 +1,327 @@ +// Sample TSX content for testing tree-sitter parsing of React and TypeScript structures +export default String.raw` +// Type Definitions (interfaces and type aliases) - spans 4+ lines +interface StandardInterfaceProps { + required: string; + numeric: number; + callback: () => void; + complex: { id: string; value: number }[]; +} + +type StandardTypeAlias = { + id: string; + name: string; + timestamp: Date; + status: 'active' | 'inactive'; +}; + +// Props Definitions (required and optional props) - spans 4+ lines +interface PropsDefinitionExample { + // Required props + requiredString: string; + requiredNumber: number; + requiredCallback: (value: string) => void; + // Optional props + optionalBoolean?: boolean; + optionalObject?: { key: string }; + optionalArray?: string[]; +} + +// Function Components (function declarations and arrow functions) - spans 4+ lines +function StandardFunctionComponent(props: StandardInterfaceProps): JSX.Element { + const { required, numeric, callback, complex } = props; + + return ( +
+ {required}: {numeric} +
+ ); +} + +// Arrow function component - spans 4+ lines +export const ArrowFunctionComponent: React.FC = ({ + requiredString, + requiredNumber, + requiredCallback, + optionalBoolean = false, + optionalObject, + optionalArray = [] +}) => { + return ( +
+ {requiredString} + {optionalArray.join(', ')} +
+ ); +}; + +// Class Components (React.Component inheritance) - spans 4+ lines +interface ClassComponentState { + count: number; + isActive: boolean; + data: string[]; + lastUpdated: Date; +} + +class StandardClassComponent extends React.Component { + constructor(props: StandardInterfaceProps) { + super(props); + this.state = { + count: 0, + isActive: true, + data: [], + lastUpdated: new Date() + }; + this.handleClick = this.handleClick.bind(this); + } + + handleClick = (event: React.MouseEvent) => { + this.setState(prevState => ({ + count: prevState.count + 1, + lastUpdated: new Date() + })); + }; + + render() { + return ( +
+

{this.props.required}

+

Count: {this.state.count}

+ +
+ ); + } +} + +// Higher Order Components (HOC patterns) - spans 4+ lines +function withLogging

( + Component: React.ComponentType

+): React.FC

{ + return function WithLoggingComponent(props: P) { + React.useEffect(() => { + console.log('Component rendered with props:', props); + return () => { + console.log('Component will unmount'); + }; + }, [props]); + + return ; + }; +} + +// Enhanced component with HOC - spans 4+ lines +const EnhancedFunctionComponent = withLogging( + StandardFunctionComponent +); + +// JSX Elements (standard and self-closing) - spans 4+ lines +const JSXElementsExample: React.FC = () => { + return ( +

+

+ Standard JSX Element +

+ Self-closing element example + console.log(e.target.value)} + className="input-field" + /> + alert("Clicked!")} + > + Member Expression Component + + {}} + complex={[{ id: '1', value: 1 }]} + /> +
+ ); +}; + +// Event Handlers (synthetic events) - spans 4+ lines +const EventHandlersComponent: React.FC = () => { + const handleClick = (event: React.MouseEvent) => { + console.log('Button clicked', event.currentTarget); + event.preventDefault(); + event.stopPropagation(); + }; + + const handleChange = (event: React.ChangeEvent) => { + const value = event.target.value; + console.log('Input value changed:', value); + }; + + const handleSubmit = (event: React.FormEvent) => { + event.preventDefault(); + console.log('Form submitted'); + }; + + return ( +
+ + +
+ ); +}; + +// State Definitions (class and hooks) - spans 4+ lines +const HooksStateComponent: React.FC = () => { + const [count, setCount] = React.useState(0); + const [user, setUser] = React.useState<{ + name: string; + age: number; + isActive: boolean; + }>({ + name: 'John', + age: 30, + isActive: true + }); + + const incrementCount = () => { + setCount(prevCount => prevCount + 1); + }; + + const updateUser = () => { + setUser({ + ...user, + age: user.age + 1, + isActive: !user.isActive + }); + }; + + return ( +
+

Count: {count}

+

User: {user.name}, {user.age}, {user.isActive ? 'Active' : 'Inactive'}

+ + +
+ ); +}; + +// Hooks Usage (built-in hooks) - spans 4+ lines +const HooksUsageComponent: React.FC<{ id: string }> = ({ id }) => { + const [data, setData] = React.useState([]); + const counter = React.useRef(0); + const prevId = React.useRef(); + + React.useEffect(() => { + console.log('Component mounted'); + fetchData(id); + + return () => { + console.log('Component unmounted'); + }; + }, [id]); + + React.useEffect(() => { + prevId.current = id; + }, [id]); + + const fetchData = React.useCallback((userId: string) => { + counter.current += 1; + // Mock fetch to avoid async/await parsing issues + setTimeout(() => { + setData(['user_data_1', 'user_data_2']); + }, 100); + setData(data); + }, []); + + const memoizedValue = React.useMemo(() => { + return { + processedData: data.map(item => item.toUpperCase()), + counter: counter.current + }; + }, [data]); + + return ( +
+

Data loaded: {memoizedValue.processedData.join(', ')}

+

Previous ID: {prevId.current}

+

Current ID: {id}

+

Fetch count: {counter.current}

+
+ ); +}; + +// Generic Components (type parameters) - spans 4+ lines +interface GenericComponentProps { + items: T[]; + renderItem: (item: T) => React.ReactNode; + keyExtractor: (item: T) => string; + onItemSelect?: (item: T) => void; +} + +function GenericListComponent({ + items, + renderItem, + keyExtractor, + onItemSelect +}: GenericComponentProps): JSX.Element { + return ( +
    + {items.map(item => ( +
  • onItemSelect && onItemSelect(item)} + > + {renderItem(item)} +
  • + ))} +
+ ); +} + +// Usage of generic component - spans 4+ lines +type UserType = { + id: string; + name: string; + email: string; + role: 'admin' | 'user'; +}; + +const GenericComponentUsage: React.FC = () => { + const users: UserType[] = [ + { id: '1', name: 'Alice', email: 'alice@example.com', role: 'admin' }, + { id: '2', name: 'Bob', email: 'bob@example.com', role: 'user' }, + { id: '3', name: 'Charlie', email: 'charlie@example.com', role: 'user' } + ]; + + return ( + + items={users} + keyExtractor={user => user.id} + renderItem={user => ( +
+ {user.name} + {user.email} + {user.role} +
+ )} + onItemSelect={user => console.log('Selected user:', user)} + /> + ); +}; +` diff --git a/src/services/tree-sitter/__tests__/fixtures/sample-typescript.ts b/src/services/tree-sitter/__tests__/fixtures/sample-typescript.ts new file mode 100644 index 00000000000..9e092ead8f5 --- /dev/null +++ b/src/services/tree-sitter/__tests__/fixtures/sample-typescript.ts @@ -0,0 +1,208 @@ +export default String.raw` +// Import statements test - inherently single-line, exempt from 4-line requirement +import React, { useState, useEffect } from 'react'; +import { render } from 'react-dom'; +import * as utils from './utils'; + +// Interface declaration test +interface TestInterfaceDefinition { + name: string; + value: number; + + methodSignature( + param1: string, + param2: number + ): string; +} + +// Type declaration test +type TestTypeDefinition = { + id: number; + name: string; + + callback: ( + param: string + ) => void; +}; + +// Enum declaration test +enum TestEnumDefinition { + First = 'FIRST', + Second = 'SECOND', + Third = 'THIRD', + Fourth = 'FOURTH' +} + +// Namespace declaration test +namespace TestNamespaceDefinition { + export interface InnerInterface { + prop: string; + } + + export function innerFunction( + param: string + ): void { + console.log(param); + } +} + +// Generic interface test +interface TestGenericInterfaceDefinition { + data: T; + metadata: U; + + process( + input: T + ): U; +} + +// Function with type annotations +function testTypedFunctionDefinition( + param1: string, + param2: number, + callback: (result: string) => void +): string { + const result = param1.repeat(param2); + callback(result); + return result; +} + +// Async function with type annotations +async function testTypedAsyncFunctionDefinition( + url: string, + options: RequestInit, + timeout: number +): Promise { + const response = await fetch(url, options); + const data = await response.json(); + return data; +} + +// Generic function test +function testGenericFunctionDefinition( + input: T, + transform: (value: T) => U +): U { + return transform(input); +} + +// Class with interface implementation +class TestTypedClassDefinition implements TestInterfaceDefinition { + // Typed class fields + private readonly #privateField: string; + static staticField: number = 42; + + constructor( + public name: string, + public value: number + ) { + this.#privateField = 'private'; + } + + // Interface method implementation + methodSignature( + param1: string, + param2: number + ): string { + return param1.repeat(param2); + } + + // Generic method + genericMethod( + input: T, + count: number + ): T[] { + return Array(count).fill(input); + } +} + +// Abstract class test +abstract class TestAbstractClassDefinition { + constructor( + protected name: string, + private value: number + ) {} + + abstract process( + input: string + ): number; + + // Concrete method + format(): string { + return this.name + + String(this.value); + } +} + +// Typed object literal +const testTypedObjectLiteralDefinition: TestTypeDefinition = { + id: 1, + name: 'test', + + callback: ( + param: string + ): void => { + console.log(param); + } +}; + +// JSX element with TypeScript props +interface TestJsxPropsDefinition { + title: string; + items: string[]; + onSelect: (item: string) => void; +} + +const testTypedJsxElementDefinition = ( + props: TestJsxPropsDefinition +): JSX.Element => { + return ( +
+
+ {props.title} +
+
+ {props.items.map(item => ( +
props.onSelect(item)}> + {item} +
+ ))} +
+
+ ); +}; + +// Decorator with TypeScript types +function testTypedDecoratorDefinition( + target: any, + propertyKey: string, + descriptor: PropertyDescriptor +): PropertyDescriptor { + const original = descriptor.value; + descriptor.value = function(...args: any[]) { + return original.apply(this, args); + }; + return descriptor; +} + +// Class with typed decorator +@testTypedDecoratorDefinition +class TestTypedDecoratedClassDefinition { + constructor( + private name: string, + protected type: string + ) {} + + @testTypedDecoratorDefinition + testDecoratedMethodDefinition( + param1: string, + param2: number + ): string { + return param1.repeat(param2); + } +} + +// Module exports - inherently single-line, exempt from 4-line requirement +export { testTypedFunctionDefinition, TestTypedClassDefinition }; +export default TestTypedDecoratedClassDefinition; +` diff --git a/src/services/tree-sitter/__tests__/fixtures/sample-vue.ts b/src/services/tree-sitter/__tests__/fixtures/sample-vue.ts new file mode 100644 index 00000000000..1a8a33c80cd --- /dev/null +++ b/src/services/tree-sitter/__tests__/fixtures/sample-vue.ts @@ -0,0 +1,93 @@ +export const sampleVue = ` + + + + + +` diff --git a/src/services/tree-sitter/__tests__/fixtures/sample-zig.ts b/src/services/tree-sitter/__tests__/fixtures/sample-zig.ts new file mode 100644 index 00000000000..661a884bf5c --- /dev/null +++ b/src/services/tree-sitter/__tests__/fixtures/sample-zig.ts @@ -0,0 +1,42 @@ +export const sampleZig = ` +const std = @import("std"); + +// A basic struct +pub const Point = struct { + x: f32, + y: f32, + + pub fn init(x: f32, y: f32) Point { + return Point{ .x = x, .y = y }; + } + + pub fn distance(self: Point) f32 { + return @sqrt(self.x * self.x + self.y * self.y); + } +}; + +// A function definition +pub fn main() !void { + const point = Point.init(3.0, 4.0); + const dist = point.distance(); + std.debug.print("Distance: {d}\n", .{dist}); +} + +// An enum definition +const Direction = enum { + North, + South, + East, + West, +}; + +// Global variables +var global_point: Point = undefined; +pub const VERSION: u32 = 1; + +// A type definition +pub const Vector = struct { + direction: Direction, + magnitude: f32, +}; +` diff --git a/src/services/tree-sitter/__tests__/helpers.ts b/src/services/tree-sitter/__tests__/helpers.ts index 522e6c1cc31..3326e1c89b3 100644 --- a/src/services/tree-sitter/__tests__/helpers.ts +++ b/src/services/tree-sitter/__tests__/helpers.ts @@ -1,9 +1,20 @@ import { jest } from "@jest/globals" -import { parseSourceCodeDefinitionsForFile } from ".." +import { parseSourceCodeDefinitionsForFile, setMinComponentLines } from ".." import * as fs from "fs/promises" import * as path from "path" import Parser from "web-tree-sitter" import tsxQuery from "../queries/tsx" +// Mock setup +jest.mock("fs/promises") +export const mockedFs = jest.mocked(fs) + +jest.mock("../../../utils/fs", () => ({ + fileExistsAtPath: jest.fn().mockImplementation(() => Promise.resolve(true)), +})) + +jest.mock("../languageParser", () => ({ + loadRequiredLanguageParsers: jest.fn(), +})) // Global debug flag - read from environment variable or default to 0 export const DEBUG = process.env.DEBUG ? parseInt(process.env.DEBUG, 10) : 0 @@ -15,9 +26,6 @@ export const debugLog = (message: string, ...args: any[]) => { } } -// Mock fs module -const mockedFs = jest.mocked(fs) - // Store the initialized TreeSitter for reuse let initializedTreeSitter: Parser | null = null @@ -65,15 +73,18 @@ export async function testParseSourceCodeDefinitions( extKey?: string } = {}, ): Promise { + // Set minimum component lines to 0 for tests + setMinComponentLines(0) + // Set default options const wasmFile = options.wasmFile || "tree-sitter-tsx.wasm" const queryString = options.queryString || tsxQuery const extKey = options.extKey || "tsx" - // Clear any previous mocks + // Clear any previous mocks and set up fs mock jest.clearAllMocks() - - // Mock fs.readFile to return our sample content + jest.mock("fs/promises") + const mockedFs = require("fs/promises") as jest.Mocked mockedFs.readFile.mockResolvedValue(content) // Get the mock function @@ -105,12 +116,12 @@ export async function testParseSourceCodeDefinitions( expect(mockedLoadRequiredLanguageParsers).toHaveBeenCalledWith([testFilePath]) expect(mockedLoadRequiredLanguageParsers).toHaveBeenCalled() - debugLog(`content:\n${content}\n\nResult:\n${result}`) + debugLog(`Result:\n${result}`) return result } // Helper function to inspect tree structure -export async function inspectTreeStructure(content: string, language: string = "typescript"): Promise { +export async function inspectTreeStructure(content: string, language: string = "typescript"): Promise { const TreeSitter = await initializeTreeSitter() const parser = new TreeSitter() const wasmPath = path.join(process.cwd(), `dist/tree-sitter-${language}.wasm`) @@ -122,41 +133,5 @@ export async function inspectTreeStructure(content: string, language: string = " // Print the tree structure debugLog(`TREE STRUCTURE (${language}):\n${tree.rootNode.toString()}`) - - // Add more detailed debug information - debugLog("\nDETAILED NODE INSPECTION:") - - // Function to recursively print node details - const printNodeDetails = (node: Parser.SyntaxNode, depth: number = 0) => { - const indent = " ".repeat(depth) - debugLog( - `${indent}Node Type: ${node.type}, Start: ${node.startPosition.row}:${node.startPosition.column}, End: ${node.endPosition.row}:${node.endPosition.column}`, - ) - - // Print children - for (let i = 0; i < node.childCount; i++) { - const child = node.child(i) - if (child) { - // For type_alias_declaration nodes, print more details - if (node.type === "type_alias_declaration") { - debugLog(`${indent} TYPE ALIAS: ${node.text}`) - } - - // For conditional_type nodes, print more details - if (node.type === "conditional_type" || child.type === "conditional_type") { - debugLog(`${indent} CONDITIONAL TYPE FOUND: ${child.text}`) - } - - // For infer_type nodes, print more details - if (node.type === "infer_type" || child.type === "infer_type") { - debugLog(`${indent} INFER TYPE FOUND: ${child.text}`) - } - - printNodeDetails(child, depth + 1) - } - } - } - - // Start recursive printing from the root node - printNodeDetails(tree.rootNode) + return tree.rootNode.toString() } diff --git a/src/services/tree-sitter/__tests__/inspectC.test.ts b/src/services/tree-sitter/__tests__/inspectC.test.ts new file mode 100644 index 00000000000..8e397ce9933 --- /dev/null +++ b/src/services/tree-sitter/__tests__/inspectC.test.ts @@ -0,0 +1,25 @@ +import { describe, it } from "@jest/globals" +import { inspectTreeStructure, testParseSourceCodeDefinitions } from "./helpers" +import { cQuery } from "../queries" +import sampleCContent from "./fixtures/sample-c" + +describe("inspectC", () => { + const testOptions = { + language: "c", + wasmFile: "tree-sitter-c.wasm", + queryString: cQuery, + extKey: "c", + } + + it("should inspect C tree structure", async () => { + await inspectTreeStructure(sampleCContent, "c") + }) + + it("should parse C definitions", async () => { + const result = await testParseSourceCodeDefinitions("test.c", sampleCContent, testOptions) + // Only verify that parsing produces output with line numbers and content + if (!result || !result.match(/\d+--\d+ \|/)) { + throw new Error("Failed to parse C definitions with line numbers") + } + }) +}) diff --git a/src/services/tree-sitter/__tests__/inspectCSS.test.ts b/src/services/tree-sitter/__tests__/inspectCSS.test.ts new file mode 100644 index 00000000000..1f3d1a6a963 --- /dev/null +++ b/src/services/tree-sitter/__tests__/inspectCSS.test.ts @@ -0,0 +1,27 @@ +import { describe, it } from "@jest/globals" +import { inspectTreeStructure, testParseSourceCodeDefinitions } from "./helpers" +import { cssQuery } from "../queries" +import sampleCSSContent from "./fixtures/sample-css" + +describe("CSS Tree-sitter Parser", () => { + const testOptions = { + language: "css", + wasmFile: "tree-sitter-css.wasm", + queryString: cssQuery, + extKey: "css", + } + + it("should properly parse CSS structures", async () => { + // First run inspectTreeStructure to get query structure output + await inspectTreeStructure(sampleCSSContent, "css") + + // Then run testParseSourceCodeDefinitions to get line numbers + const result = await testParseSourceCodeDefinitions("test.css", sampleCSSContent, testOptions) + expect(result).toBeDefined() + if (!result) { + throw new Error("No result returned from parser") + } + expect(result).toMatch(/\d+--\d+ \|/) + expect(result.split("\n").length).toBeGreaterThan(1) + }) +}) diff --git a/src/services/tree-sitter/__tests__/inspectCSharp.test.ts b/src/services/tree-sitter/__tests__/inspectCSharp.test.ts new file mode 100644 index 00000000000..d8d01839418 --- /dev/null +++ b/src/services/tree-sitter/__tests__/inspectCSharp.test.ts @@ -0,0 +1,24 @@ +import { describe, it } from "@jest/globals" +import { inspectTreeStructure, testParseSourceCodeDefinitions } from "./helpers" +import { csharpQuery } from "../queries" +import sampleCSharpContent from "./fixtures/sample-c-sharp" + +describe("inspectCSharp", () => { + const testOptions = { + language: "c_sharp", + wasmFile: "tree-sitter-c_sharp.wasm", + queryString: csharpQuery, + extKey: "cs", + } + + it("should inspect C# tree structure", async () => { + // Should execute without throwing + await expect(inspectTreeStructure(sampleCSharpContent, "c_sharp")).resolves.not.toThrow() + }) + + it("should parse C# definitions", async () => { + const result = await testParseSourceCodeDefinitions("test.cs", sampleCSharpContent, testOptions) + expect(result).toBeDefined() + expect(result).toMatch(/\d+--\d+ \|/) + }) +}) diff --git a/src/services/tree-sitter/__tests__/inspectCpp.test.ts b/src/services/tree-sitter/__tests__/inspectCpp.test.ts new file mode 100644 index 00000000000..b6e28cf19a5 --- /dev/null +++ b/src/services/tree-sitter/__tests__/inspectCpp.test.ts @@ -0,0 +1,23 @@ +import { describe, it, expect } from "@jest/globals" +import { inspectTreeStructure, testParseSourceCodeDefinitions } from "./helpers" +import { cppQuery } from "../queries" +import sampleCppContent from "./fixtures/sample-cpp" + +describe("C++ Tree-sitter Parser", () => { + const testOptions = { + language: "cpp", + wasmFile: "tree-sitter-cpp.wasm", + queryString: cppQuery, + extKey: "cpp", + } + + it("should properly parse structures", async () => { + // First run inspectTreeStructure to get query structure output + await inspectTreeStructure(sampleCppContent, "cpp") + + // Then run testParseSourceCodeDefinitions to get line numbers + const result = await testParseSourceCodeDefinitions("test.cpp", sampleCppContent, testOptions) + expect(result).toBeDefined() + expect(result).toMatch(/\d+--\d+ \|/) + }) +}) diff --git a/src/services/tree-sitter/__tests__/inspectElisp.test.ts b/src/services/tree-sitter/__tests__/inspectElisp.test.ts new file mode 100644 index 00000000000..242019177be --- /dev/null +++ b/src/services/tree-sitter/__tests__/inspectElisp.test.ts @@ -0,0 +1,29 @@ +import { describe, it } from "@jest/globals" +import { inspectTreeStructure, testParseSourceCodeDefinitions } from "./helpers" +import { elispQuery } from "../queries/elisp" +import sampleElispContent from "./fixtures/sample-elisp" + +describe("inspectElisp", () => { + const testOptions = { + language: "elisp", + wasmFile: "tree-sitter-elisp.wasm", + queryString: elispQuery, + extKey: "el", + } + + it("should validate Elisp tree structure inspection", async () => { + const result = await inspectTreeStructure(sampleElispContent, "elisp") + expect(result).toBeDefined() + expect(result.length).toBeGreaterThan(0) + }) + + it("should validate Elisp definitions parsing", async () => { + const result = await testParseSourceCodeDefinitions("test.el", sampleElispContent, testOptions) + expect(result).toBeDefined() + expect(result).toMatch(/\d+--\d+ \|/) // Verify line number format + + // Verify some sample content is parsed + expect(result).toMatch(/defun test-function/) + expect(result).toMatch(/defmacro test-macro/) + }) +}) diff --git a/src/services/tree-sitter/__tests__/inspectElixir.test.ts b/src/services/tree-sitter/__tests__/inspectElixir.test.ts new file mode 100644 index 00000000000..a756b1cd9f7 --- /dev/null +++ b/src/services/tree-sitter/__tests__/inspectElixir.test.ts @@ -0,0 +1,26 @@ +import { describe, it } from "@jest/globals" +import { inspectTreeStructure, testParseSourceCodeDefinitions } from "./helpers" +import { elixirQuery } from "../queries" +import sampleElixirContent from "./fixtures/sample-elixir" + +describe("inspectElixir", () => { + const testOptions = { + language: "elixir", + wasmFile: "tree-sitter-elixir.wasm", + queryString: elixirQuery, + extKey: "ex", + } + + it("should inspect Elixir tree structure", async () => { + const result = await inspectTreeStructure(sampleElixirContent, "elixir") + expect(result).toBeDefined() + expect(result.length).toBeGreaterThan(0) + }) + + it("should parse Elixir definitions", async () => { + const result = await testParseSourceCodeDefinitions("test.ex", sampleElixirContent, testOptions) + expect(result).toBeDefined() + expect(result).toContain("--") + expect(result).toMatch(/\d+--\d+ \|/) + }) +}) diff --git a/src/services/tree-sitter/__tests__/inspectEmbeddedTemplate.test.ts b/src/services/tree-sitter/__tests__/inspectEmbeddedTemplate.test.ts new file mode 100644 index 00000000000..4d2157cca62 --- /dev/null +++ b/src/services/tree-sitter/__tests__/inspectEmbeddedTemplate.test.ts @@ -0,0 +1,24 @@ +import { describe, it } from "@jest/globals" +import { inspectTreeStructure, testParseSourceCodeDefinitions } from "./helpers" +import { embeddedTemplateQuery } from "../queries" +import sampleEmbeddedTemplateContent from "./fixtures/sample-embedded_template" + +describe("inspectEmbeddedTemplate", () => { + const testOptions = { + language: "embedded_template", + wasmFile: "tree-sitter-embedded_template.wasm", + queryString: embeddedTemplateQuery, + extKey: "erb", // Match the file extension we're using + } + + it("should inspect embedded template tree structure", async () => { + const result = await inspectTreeStructure(sampleEmbeddedTemplateContent, "embedded_template") + expect(result).toBeTruthy() + }) + + it("should parse embedded template definitions", async () => { + const result = await testParseSourceCodeDefinitions("test.erb", sampleEmbeddedTemplateContent, testOptions) + expect(result).toBeTruthy() + expect(result).toMatch(/\d+--\d+ \|/) // Verify line number format + }) +}) diff --git a/src/services/tree-sitter/__tests__/inspectGo.test.ts b/src/services/tree-sitter/__tests__/inspectGo.test.ts new file mode 100644 index 00000000000..185867d1eba --- /dev/null +++ b/src/services/tree-sitter/__tests__/inspectGo.test.ts @@ -0,0 +1,24 @@ +import { describe, it, expect } from "@jest/globals" +import { inspectTreeStructure, testParseSourceCodeDefinitions } from "./helpers" +import sampleGoContent from "./fixtures/sample-go" +import goQuery from "../queries/go" + +describe("Go Tree-sitter Parser", () => { + // Test 1: Get query structure output + it("should inspect tree structure", async () => { + await inspectTreeStructure(sampleGoContent, "go") + }) + + // Test 2: Get line numbers + it("should parse source code definitions", async () => { + const testOptions = { + language: "go", + wasmFile: "tree-sitter-go.wasm", + queryString: goQuery, + extKey: "go", + } + + const result = await testParseSourceCodeDefinitions("file.go", sampleGoContent, testOptions) + expect(result).toBeDefined() + }) +}) diff --git a/src/services/tree-sitter/__tests__/inspectHtml.test.ts b/src/services/tree-sitter/__tests__/inspectHtml.test.ts new file mode 100644 index 00000000000..bc7a2c34c26 --- /dev/null +++ b/src/services/tree-sitter/__tests__/inspectHtml.test.ts @@ -0,0 +1,24 @@ +import { describe, it } from "@jest/globals" +import { inspectTreeStructure, testParseSourceCodeDefinitions } from "./helpers" +import { htmlQuery } from "../queries" +import { sampleHtmlContent } from "./fixtures/sample-html" + +describe("inspectHtml", () => { + const testOptions = { + language: "html", + wasmFile: "tree-sitter-html.wasm", + queryString: htmlQuery, + extKey: "html", + } + + it("should inspect HTML tree structure", async () => { + // Should execute without error + await expect(inspectTreeStructure(sampleHtmlContent, "html")).resolves.not.toThrow() + }) + + it("should parse HTML definitions", async () => { + const result = await testParseSourceCodeDefinitions("test.html", sampleHtmlContent, testOptions) + expect(result).toBeDefined() + expect(result).toMatch(/\d+--\d+ \| { + const testOptions = { + language: "java", + wasmFile: "tree-sitter-java.wasm", + queryString: javaQuery, + extKey: "java", + } + + it("should inspect Java tree structure", async () => { + const result = await inspectTreeStructure(sampleJavaContent, "java") + expect(result).toBeTruthy() + }) + + it("should parse Java definitions", async () => { + const result = await testParseSourceCodeDefinitions("test.java", sampleJavaContent, testOptions) + expect(result).toBeTruthy() + expect(result).toMatch(/\d+--\d+ \| /) // Verify line number format + }) +}) diff --git a/src/services/tree-sitter/__tests__/inspectJavaScript.test.ts b/src/services/tree-sitter/__tests__/inspectJavaScript.test.ts new file mode 100644 index 00000000000..c5d7387473b --- /dev/null +++ b/src/services/tree-sitter/__tests__/inspectJavaScript.test.ts @@ -0,0 +1,25 @@ +import { describe, it } from "@jest/globals" +import { inspectTreeStructure, testParseSourceCodeDefinitions } from "./helpers" +import { javascriptQuery } from "../queries" +import sampleJavaScriptContent from "./fixtures/sample-javascript" + +describe("inspectJavaScript", () => { + const testOptions = { + language: "javascript", + wasmFile: "tree-sitter-javascript.wasm", + queryString: javascriptQuery, + extKey: "js", + } + + it("should inspect JavaScript tree structure", async () => { + // Should not throw + await expect(inspectTreeStructure(sampleJavaScriptContent, "javascript")).resolves.not.toThrow() + }) + + it("should parse JavaScript definitions", async () => { + const result = await testParseSourceCodeDefinitions("test.js", sampleJavaScriptContent, testOptions) + expect(result).toBeDefined() + expect(result).toMatch(/\d+--\d+ \| /) + expect(result).toMatch(/function testFunctionDefinition/) + }) +}) diff --git a/src/services/tree-sitter/__tests__/inspectJson.test.ts b/src/services/tree-sitter/__tests__/inspectJson.test.ts new file mode 100644 index 00000000000..e8c3506ae60 --- /dev/null +++ b/src/services/tree-sitter/__tests__/inspectJson.test.ts @@ -0,0 +1,21 @@ +import { describe, it } from "@jest/globals" +import { inspectTreeStructure, testParseSourceCodeDefinitions } from "./helpers" +import { javascriptQuery } from "../queries" +import sampleJsonContent from "./fixtures/sample-json" + +describe("inspectJson", () => { + const testOptions = { + language: "javascript", + wasmFile: "tree-sitter-javascript.wasm", + queryString: javascriptQuery, + extKey: "json", + } + + it("should inspect JSON tree structure", async () => { + await inspectTreeStructure(sampleJsonContent, "json") + }) + + it("should parse JSON definitions", async () => { + await testParseSourceCodeDefinitions("test.json", sampleJsonContent, testOptions) + }) +}) diff --git a/src/services/tree-sitter/__tests__/inspectKotlin.test.ts b/src/services/tree-sitter/__tests__/inspectKotlin.test.ts new file mode 100644 index 00000000000..df9a3e557bd --- /dev/null +++ b/src/services/tree-sitter/__tests__/inspectKotlin.test.ts @@ -0,0 +1,21 @@ +import { describe, it } from "@jest/globals" +import { inspectTreeStructure, testParseSourceCodeDefinitions } from "./helpers" +import { kotlinQuery } from "../queries" +import sampleKotlinContent from "./fixtures/sample-kotlin" + +describe("inspectKotlin", () => { + const testOptions = { + language: "kotlin", + wasmFile: "tree-sitter-kotlin.wasm", + queryString: kotlinQuery, + extKey: "kt", + } + + it("should inspect Kotlin tree structure", async () => { + await inspectTreeStructure(sampleKotlinContent, "kotlin") + }) + + it("should parse Kotlin definitions", async () => { + await testParseSourceCodeDefinitions("test.kt", sampleKotlinContent, testOptions) + }) +}) diff --git a/src/services/tree-sitter/__tests__/inspectLua.test.ts b/src/services/tree-sitter/__tests__/inspectLua.test.ts new file mode 100644 index 00000000000..0868bbd5d64 --- /dev/null +++ b/src/services/tree-sitter/__tests__/inspectLua.test.ts @@ -0,0 +1,23 @@ +import { describe, it } from "@jest/globals" +import { inspectTreeStructure, testParseSourceCodeDefinitions, debugLog } from "./helpers" +import { luaQuery } from "../queries" +import sampleLuaContent from "./fixtures/sample-lua" + +describe("inspectLua", () => { + const testOptions = { + language: "lua", + wasmFile: "tree-sitter-lua.wasm", + queryString: luaQuery, + extKey: "lua", + } + + it("should inspect Lua tree structure", async () => { + await inspectTreeStructure(sampleLuaContent, "lua") + }) + + it("should parse Lua definitions", async () => { + const result = await testParseSourceCodeDefinitions("file.lua", sampleLuaContent, testOptions) + expect(result).toBeDefined() // Confirm parse succeeded + debugLog("Lua parse result:", result) + }) +}) diff --git a/src/services/tree-sitter/__tests__/inspectOCaml.test.ts b/src/services/tree-sitter/__tests__/inspectOCaml.test.ts new file mode 100644 index 00000000000..0a18cb87c10 --- /dev/null +++ b/src/services/tree-sitter/__tests__/inspectOCaml.test.ts @@ -0,0 +1,27 @@ +import { describe, it, expect } from "@jest/globals" +import { inspectTreeStructure, testParseSourceCodeDefinitions } from "./helpers" +import { ocamlQuery } from "../queries" +import { sampleOCaml } from "./fixtures/sample-ocaml" + +describe("inspectOCaml", () => { + const testOptions = { + language: "ocaml", + wasmFile: "tree-sitter-ocaml.wasm", + queryString: ocamlQuery, + extKey: "ml", + } + + it("should inspect OCaml tree structure", async () => { + const result = await inspectTreeStructure(sampleOCaml, "ocaml") + expect(result).toBeDefined() + expect(result.length).toBeGreaterThan(0) + }) + + it("should parse OCaml definitions", async () => { + const result = await testParseSourceCodeDefinitions("test.ml", sampleOCaml, testOptions) + expect(result).toBeDefined() + expect(result).toMatch(/\d+--\d+ \| module StringSet/) + expect(result).toMatch(/\d+--\d+ \| type shape/) + expect(result).toMatch(/\d+--\d+ \| let rec process_list/) + }) +}) diff --git a/src/services/tree-sitter/__tests__/inspectPhp.test.ts b/src/services/tree-sitter/__tests__/inspectPhp.test.ts new file mode 100644 index 00000000000..a120b2bcd72 --- /dev/null +++ b/src/services/tree-sitter/__tests__/inspectPhp.test.ts @@ -0,0 +1,21 @@ +import { describe, it } from "@jest/globals" +import { inspectTreeStructure, testParseSourceCodeDefinitions } from "./helpers" +import { phpQuery } from "../queries" +import samplePhpContent from "./fixtures/sample-php" + +describe("inspectPhp", () => { + const testOptions = { + language: "php", + wasmFile: "tree-sitter-php.wasm", + queryString: phpQuery, + extKey: "php", + } + + it("should inspect PHP tree structure", async () => { + await inspectTreeStructure(samplePhpContent, "php") + }) + + it("should parse PHP definitions", async () => { + await testParseSourceCodeDefinitions("test.php", samplePhpContent, testOptions) + }) +}) diff --git a/src/services/tree-sitter/__tests__/inspectPython.test.ts b/src/services/tree-sitter/__tests__/inspectPython.test.ts new file mode 100644 index 00000000000..99c0132fac8 --- /dev/null +++ b/src/services/tree-sitter/__tests__/inspectPython.test.ts @@ -0,0 +1,24 @@ +import { inspectTreeStructure, testParseSourceCodeDefinitions } from "./helpers" +import { samplePythonContent } from "./fixtures/sample-python" +import { pythonQuery } from "../queries" + +// Python test options +const pythonOptions = { + language: "python", + wasmFile: "tree-sitter-python.wasm", + queryString: pythonQuery, + extKey: "py", +} + +describe("Python Tree-sitter Parser", () => { + it("should successfully parse and inspect Python code", async () => { + // Verify tree structure inspection succeeds + const inspectResult = await inspectTreeStructure(samplePythonContent, "python") + expect(inspectResult).toBeDefined() + + // Verify source code definitions parsing succeeds + const parseResult = await testParseSourceCodeDefinitions("test.py", samplePythonContent, pythonOptions) + expect(parseResult).toMatch(/\d+--\d+ \|/) // Verify line number format + expect(parseResult).toContain("class") // Basic content verification + }) +}) diff --git a/src/services/tree-sitter/__tests__/inspectRuby.test.ts b/src/services/tree-sitter/__tests__/inspectRuby.test.ts new file mode 100644 index 00000000000..f95c080114c --- /dev/null +++ b/src/services/tree-sitter/__tests__/inspectRuby.test.ts @@ -0,0 +1,22 @@ +import { describe, it } from "@jest/globals" +import { inspectTreeStructure, testParseSourceCodeDefinitions } from "./helpers" +import { rubyQuery } from "../queries" +import sampleRubyContent from "./fixtures/sample-ruby" + +describe("inspectRuby", () => { + const testOptions = { + language: "ruby", + wasmFile: "tree-sitter-ruby.wasm", + queryString: rubyQuery, + extKey: "rb", + } + + it("should inspect Ruby tree structure and parse definitions", async () => { + // First inspect the tree structure + await inspectTreeStructure(sampleRubyContent, "ruby") + + // Then validate definition parsing + const result = await testParseSourceCodeDefinitions("test.rb", sampleRubyContent, testOptions) + expect(result).toMatch(/\d+--\d+ \|/) // Verify line number format + }) +}) diff --git a/src/services/tree-sitter/__tests__/inspectRust.test.ts b/src/services/tree-sitter/__tests__/inspectRust.test.ts new file mode 100644 index 00000000000..2d7c1896d5a --- /dev/null +++ b/src/services/tree-sitter/__tests__/inspectRust.test.ts @@ -0,0 +1,33 @@ +import { describe, it, expect } from "@jest/globals" +import { inspectTreeStructure, testParseSourceCodeDefinitions, debugLog } from "./helpers" +import { rustQuery } from "../queries" +import sampleRustContent from "./fixtures/sample-rust" + +describe("inspectRust", () => { + const testOptions = { + language: "rust", + wasmFile: "tree-sitter-rust.wasm", + queryString: rustQuery, + extKey: "rs", + } + + it("should inspect Rust tree structure", async () => { + // This test only validates that inspectTreeStructure succeeds + // It will output debug information when DEBUG=1 is set + await inspectTreeStructure(sampleRustContent, "rust") + }) + + it("should parse Rust definitions", async () => { + // This test validates that parsing produces output with line numbers + const result = await testParseSourceCodeDefinitions("test.rs", sampleRustContent, testOptions) + + // Only validate that we get some output with the expected format + expect(result).toBeTruthy() + + // Check that the output contains line numbers in the format "N--M | content" + expect(result).toMatch(/\d+--\d+ \|/) + + // Output for debugging purposes + debugLog("Rust definitions parsing succeeded") + }) +}) diff --git a/src/services/tree-sitter/__tests__/inspectScala.test.ts b/src/services/tree-sitter/__tests__/inspectScala.test.ts new file mode 100644 index 00000000000..a8323fb2841 --- /dev/null +++ b/src/services/tree-sitter/__tests__/inspectScala.test.ts @@ -0,0 +1,25 @@ +import { describe, it } from "@jest/globals" +import { inspectTreeStructure, testParseSourceCodeDefinitions, debugLog } from "./helpers" +import { scalaQuery } from "../queries" +import { sampleScala } from "./fixtures/sample-scala" + +describe("inspectScala", () => { + const testOptions = { + language: "scala", + wasmFile: "tree-sitter-scala.wasm", + queryString: scalaQuery, + extKey: "scala", + } + + it("should inspect Scala tree structure", async () => { + const result = await inspectTreeStructure(sampleScala, "scala") + expect(result).toBeDefined() + }) + + it("should parse Scala definitions", async () => { + const result = await testParseSourceCodeDefinitions("test.scala", sampleScala, testOptions) + expect(result).toBeDefined() + expect(result).toMatch(/\d+--\d+ \|/) + debugLog("Scala parse result:", result) + }) +}) diff --git a/src/services/tree-sitter/__tests__/inspectSolidity.test.ts b/src/services/tree-sitter/__tests__/inspectSolidity.test.ts new file mode 100644 index 00000000000..94492c297a3 --- /dev/null +++ b/src/services/tree-sitter/__tests__/inspectSolidity.test.ts @@ -0,0 +1,26 @@ +import { describe, it } from "@jest/globals" +import { debugLog, inspectTreeStructure, testParseSourceCodeDefinitions } from "./helpers" +import { solidityQuery } from "../queries" +import { sampleSolidity } from "./fixtures/sample-solidity" + +describe("inspectSolidity", () => { + const testOptions = { + language: "solidity", + wasmFile: "tree-sitter-solidity.wasm", + queryString: solidityQuery, + extKey: "sol", + } + + it("should inspect Solidity tree structure", async () => { + const result = await inspectTreeStructure(sampleSolidity, "solidity") + expect(result).toBeDefined() + debugLog("Tree Structure:", result) + }) + + it("should parse Solidity definitions", async () => { + const result = await testParseSourceCodeDefinitions("test.sol", sampleSolidity, testOptions) + expect(result).toBeDefined() + expect(result).toMatch(/\d+--\d+ \|/) + debugLog("Parse Result:", result) + }) +}) diff --git a/src/services/tree-sitter/__tests__/inspectSwift.test.ts b/src/services/tree-sitter/__tests__/inspectSwift.test.ts new file mode 100644 index 00000000000..8c515963f73 --- /dev/null +++ b/src/services/tree-sitter/__tests__/inspectSwift.test.ts @@ -0,0 +1,30 @@ +import { describe, it, expect } from "@jest/globals" +import { inspectTreeStructure, testParseSourceCodeDefinitions, debugLog } from "./helpers" +import { swiftQuery } from "../queries" +import sampleSwiftContent from "./fixtures/sample-swift" + +describe("inspectSwift", () => { + const testOptions = { + language: "swift", + wasmFile: "tree-sitter-swift.wasm", + queryString: swiftQuery, + extKey: "swift", + } + + it("should inspect Swift tree structure", async () => { + // Should execute without throwing + await expect(inspectTreeStructure(sampleSwiftContent, "swift")).resolves.not.toThrow() + }) + + it("should parse Swift definitions", async () => { + // This test validates that testParseSourceCodeDefinitions produces output + const result = await testParseSourceCodeDefinitions("test.swift", sampleSwiftContent, testOptions) + expect(result).toBeDefined() + + // Check that the output format includes line numbers and content + if (result) { + expect(result).toMatch(/\d+--\d+ \| .+/) + debugLog("Swift parsing test completed successfully") + } + }) +}) diff --git a/src/services/tree-sitter/__tests__/inspectSystemRDL.test.ts b/src/services/tree-sitter/__tests__/inspectSystemRDL.test.ts new file mode 100644 index 00000000000..f7d2266a70b --- /dev/null +++ b/src/services/tree-sitter/__tests__/inspectSystemRDL.test.ts @@ -0,0 +1,22 @@ +import { describe, it } from "@jest/globals" +import { inspectTreeStructure, testParseSourceCodeDefinitions, debugLog } from "./helpers" +import systemrdlQuery from "../queries/systemrdl" +import sampleSystemRDLContent from "./fixtures/sample-systemrdl" + +describe("inspectSystemRDL", () => { + const testOptions = { + language: "systemrdl", + wasmFile: "tree-sitter-systemrdl.wasm", + queryString: systemrdlQuery, + extKey: "rdl", + } + + it("should inspect SystemRDL tree structure", async () => { + await inspectTreeStructure(sampleSystemRDLContent, "systemrdl") + }) + + it("should parse SystemRDL definitions", async () => { + const result = await testParseSourceCodeDefinitions("test.rdl", sampleSystemRDLContent, testOptions) + debugLog("SystemRDL parse result:", result) + }) +}) diff --git a/src/services/tree-sitter/__tests__/inspectTLAPlus.test.ts b/src/services/tree-sitter/__tests__/inspectTLAPlus.test.ts new file mode 100644 index 00000000000..95094b45181 --- /dev/null +++ b/src/services/tree-sitter/__tests__/inspectTLAPlus.test.ts @@ -0,0 +1,21 @@ +import { describe, it } from "@jest/globals" +import { inspectTreeStructure, testParseSourceCodeDefinitions } from "./helpers" +import { tlaPlusQuery } from "../queries" +import sampleTLAPlusContent from "./fixtures/sample-tlaplus" + +describe("inspectTLAPlus", () => { + const testOptions = { + language: "tlaplus", + wasmFile: "tree-sitter-tlaplus.wasm", + queryString: tlaPlusQuery, + extKey: "tla", + } + + it("should inspect TLA+ tree structure", async () => { + await inspectTreeStructure(sampleTLAPlusContent, "tlaplus") + }) + + it("should parse TLA+ definitions", async () => { + await testParseSourceCodeDefinitions("test.tla", sampleTLAPlusContent, testOptions) + }) +}) diff --git a/src/services/tree-sitter/__tests__/inspectTOML.test.ts b/src/services/tree-sitter/__tests__/inspectTOML.test.ts new file mode 100644 index 00000000000..3e1e733294f --- /dev/null +++ b/src/services/tree-sitter/__tests__/inspectTOML.test.ts @@ -0,0 +1,21 @@ +import { describe, it } from "@jest/globals" +import { inspectTreeStructure, testParseSourceCodeDefinitions } from "./helpers" +import { tomlQuery } from "../queries" +import { sampleToml } from "./fixtures/sample-toml" + +describe("inspectTOML", () => { + const testOptions = { + language: "toml", + wasmFile: "tree-sitter-toml.wasm", + queryString: tomlQuery, + extKey: "toml", + } + + it("should inspect TOML tree structure", async () => { + await inspectTreeStructure(sampleToml, "toml") + }) + + it("should parse TOML definitions", async () => { + await testParseSourceCodeDefinitions("test.toml", sampleToml, testOptions) + }) +}) diff --git a/src/services/tree-sitter/__tests__/inspectTsx.test.ts b/src/services/tree-sitter/__tests__/inspectTsx.test.ts new file mode 100644 index 00000000000..acf59765789 --- /dev/null +++ b/src/services/tree-sitter/__tests__/inspectTsx.test.ts @@ -0,0 +1,30 @@ +import { describe, it, expect } from "@jest/globals" +import { inspectTreeStructure, testParseSourceCodeDefinitions, debugLog } from "./helpers" +import sampleTsxContent from "./fixtures/sample-tsx" + +describe("inspectTsx", () => { + const testOptions = { + language: "tsx", + wasmFile: "tree-sitter-tsx.wasm", + } + + it("should inspect TSX tree structure", async () => { + // This test only validates that the function executes without error + await inspectTreeStructure(sampleTsxContent, "tsx") + // No expectations - just verifying it runs + }) + + it("should parse TSX definitions and produce line number output", async () => { + // Execute parsing and capture the result + const result = await testParseSourceCodeDefinitions("test.tsx", sampleTsxContent, testOptions) + + // Validate that the result is defined + expect(result).toBeDefined() + + // Validate that the result contains line number output format (N--M | content) + expect(result).toMatch(/\d+--\d+ \|/) + + // Debug output the result for inspection + debugLog("TSX Parse Result Sample:", result?.substring(0, 500) + "...") + }) +}) diff --git a/src/services/tree-sitter/__tests__/inspectTypeScript.test.ts b/src/services/tree-sitter/__tests__/inspectTypeScript.test.ts new file mode 100644 index 00000000000..f7f58a85339 --- /dev/null +++ b/src/services/tree-sitter/__tests__/inspectTypeScript.test.ts @@ -0,0 +1,25 @@ +import { describe, it } from "@jest/globals" +import { inspectTreeStructure, testParseSourceCodeDefinitions } from "./helpers" +import { typescriptQuery } from "../queries" +import sampleTypeScriptContent from "./fixtures/sample-typescript" + +describe("inspectTypeScript", () => { + const testOptions = { + language: "typescript", + wasmFile: "tree-sitter-typescript.wasm", + queryString: typescriptQuery, + extKey: "ts", + } + + it("should successfully inspect TypeScript tree structure", async () => { + // Should execute without throwing + await expect(inspectTreeStructure(sampleTypeScriptContent, "typescript")).resolves.not.toThrow() + }) + + it("should successfully parse TypeScript definitions", async () => { + const result = await testParseSourceCodeDefinitions("test.ts", sampleTypeScriptContent, testOptions) + expect(result).toBeDefined() + expect(result).toMatch(/\d+--\d+ \|/) // Verify line number format + expect(result).toMatch(/interface TestInterfaceDefinition/) // Verify some content + }) +}) diff --git a/src/services/tree-sitter/__tests__/inspectVue.test.ts b/src/services/tree-sitter/__tests__/inspectVue.test.ts new file mode 100644 index 00000000000..08695f6bfe5 --- /dev/null +++ b/src/services/tree-sitter/__tests__/inspectVue.test.ts @@ -0,0 +1,22 @@ +import { describe, it } from "@jest/globals" +import { inspectTreeStructure, testParseSourceCodeDefinitions, debugLog } from "./helpers" +import { vueQuery } from "../queries/vue" +import { sampleVue } from "./fixtures/sample-vue" + +describe("Vue Parser", () => { + const testOptions = { + language: "vue", + wasmFile: "tree-sitter-vue.wasm", + queryString: vueQuery, + extKey: "vue", + } + + it("should inspect Vue tree structure", async () => { + await inspectTreeStructure(sampleVue, "vue") + }) + + it("should parse Vue definitions", async () => { + const result = await testParseSourceCodeDefinitions("test.vue", sampleVue, testOptions) + debugLog("Vue parse result:", result) + }) +}) diff --git a/src/services/tree-sitter/__tests__/inspectZig.test.ts b/src/services/tree-sitter/__tests__/inspectZig.test.ts new file mode 100644 index 00000000000..62037bd4b8c --- /dev/null +++ b/src/services/tree-sitter/__tests__/inspectZig.test.ts @@ -0,0 +1,20 @@ +import { describe, it, expect } from "@jest/globals" +import { testParseSourceCodeDefinitions, inspectTreeStructure } from "./helpers" +import { sampleZig } from "./fixtures/sample-zig" +import { zigQuery } from "../queries" + +describe("Zig Tree-sitter Parser", () => { + it("should inspect tree structure", async () => { + await inspectTreeStructure(sampleZig, "zig") + }) + + it("should parse source code definitions", async () => { + const result = await testParseSourceCodeDefinitions("file.zig", sampleZig, { + language: "zig", + wasmFile: "tree-sitter-zig.wasm", + queryString: zigQuery, + extKey: "zig", + }) + expect(result).toBeDefined() + }) +}) diff --git a/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.c-sharp.test.ts b/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.c-sharp.test.ts new file mode 100644 index 00000000000..52facd4c4cd --- /dev/null +++ b/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.c-sharp.test.ts @@ -0,0 +1,112 @@ +/* +TODO: The following structures can be parsed by tree-sitter but lack query support: + +1. Using Directives: + (using_directive) - Can be parsed by tree-sitter but not appearing in output despite query pattern +*/ + +import { describe, expect, it, jest, beforeEach } from "@jest/globals" +import { csharpQuery } from "../queries" +import { testParseSourceCodeDefinitions } from "./helpers" +import sampleCSharpContent from "./fixtures/sample-c-sharp" + +// C# test options +const csharpOptions = { + language: "c_sharp", + wasmFile: "tree-sitter-c_sharp.wasm", + queryString: csharpQuery, + extKey: "cs", +} + +// Mock file system operations +jest.mock("fs/promises") + +// Mock loadRequiredLanguageParsers +jest.mock("../languageParser", () => ({ + loadRequiredLanguageParsers: jest.fn(), +})) + +// Mock fileExistsAtPath to return true for our test paths +jest.mock("../../../utils/fs", () => ({ + fileExistsAtPath: jest.fn().mockImplementation(() => Promise.resolve(true)), +})) + +describe("parseSourceCodeDefinitionsForFile with C#", () => { + let parseResult: string | undefined + + beforeAll(async () => { + // Cache parse result for all tests + const result = await testParseSourceCodeDefinitions("/test/file.cs", sampleCSharpContent, csharpOptions) + if (!result) { + throw new Error("Failed to parse C# source code definitions") + } + parseResult = result + }) + + beforeEach(() => { + jest.clearAllMocks() + expect(parseResult).toBeDefined() + }) + + it("should parse namespace declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*namespace TestNamespaceDefinition/) + }) + + it("should parse file-scoped namespace declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*namespace TestFileScopedNamespaceDefinition/) + }) + + it("should parse class declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*public class TestClassDefinition/) + }) + + it("should parse interface declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*public interface ITestInterfaceDefinition/) + }) + + it("should parse enum declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*public enum TestEnumDefinition/) + }) + + it("should parse method declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*void TestInterfaceMethod/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*public async Task TestAsyncMethodDefinition/) + }) + + it("should parse property declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*public string TestPropertyDefinition/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*public required string TestRequiredProperty/) + }) + + it("should parse event declarations", () => { + expect(parseResult).toMatch( + /\d+--\d+ \|\s*public event EventHandler TestEventDefinition/, + ) + }) + + it("should parse delegate declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*public delegate void TestDelegateDefinition/) + }) + + it("should parse struct declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*public struct TestStructDefinition/) + }) + + it("should parse record declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*public record TestRecordDefinition/) + }) + + it("should parse attribute declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*\[AttributeUsage/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*\[TestAttributeDefinition/) + }) + + it("should parse generic type parameters", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*public class TestGenericClassDefinition/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*public T TestGenericMethodDefinition/) + }) + + it("should parse LINQ expressions", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*var result = from num in _numbers/) + }) +}) diff --git a/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.c.test.ts b/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.c.test.ts new file mode 100644 index 00000000000..020625d5c3e --- /dev/null +++ b/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.c.test.ts @@ -0,0 +1,114 @@ +import { describe, it, beforeAll } from "@jest/globals" +import { testParseSourceCodeDefinitions } from "./helpers" +import { cQuery } from "../queries" +import sampleCContent from "./fixtures/sample-c" + +describe("C Source Code Definition Tests", () => { + let parseResult: string + + beforeAll(async () => { + const result = await testParseSourceCodeDefinitions("test.c", sampleCContent, { + language: "c", + wasmFile: "tree-sitter-c.wasm", + queryString: cQuery, + extKey: "c", + }) + if (!result || !result.match(/\d+--\d+ \|/)) { + throw new Error("Failed to parse C tree structure") + } + parseResult = result + }) + + it("should parse function declarations and definitions", () => { + // Regular function declarations + expect(parseResult).toMatch(/\d+--\d+ \|\s*void multiline_prototype\(/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*void void_param_prototype\(/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*void function_pointer_prototype\(/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*int variadic_prototype\(/) + + // Function definitions + expect(parseResult).toMatch(/\d+--\d+ \|\s*int basic_multitype_function\(/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*void array_param_function\(/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*void pointer_param_function\(/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*int variadic_impl_function\(/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*void test_pointer_function\(/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*int test_variadic_function\(/) + }) + + it("should parse struct definitions", () => { + // Regular structs + expect(parseResult).toMatch(/\d+--\d+ \|\s*struct nested_struct \{/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*struct bitfield_struct \{/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*struct callback_struct \{/) + + // Special struct types + expect(parseResult).toMatch(/\d+--\d+ \|\s*struct anonymous_union_struct \{/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*struct aligned_struct \{/) + + // Global struct + expect(parseResult).toMatch(/\d+--\d+ \|\s*static struct config_struct \{/) + }) + + it("should parse union definitions", () => { + // Regular unions + expect(parseResult).toMatch(/\d+--\d+ \|\s*union multitype_data_union \{/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*union bitfield_union \{/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*union basic_types_struct \{/) + + // Anonymous union in struct + expect(parseResult).toMatch(/\d+--\d+ \|\s*struct anonymous_union_struct \{/) + }) + + it("should parse enum definitions", () => { + // Sequential value enums + expect(parseResult).toMatch(/\d+--\d+ \|\s*enum sequential_value_enum \{/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*enum TestBasicEnum \{/) + + // Explicit value enums + expect(parseResult).toMatch(/\d+--\d+ \|\s*enum explicit_value_enum \{/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*enum TestValuedEnum \{/) + + // Mixed value enums + expect(parseResult).toMatch(/\d+--\d+ \|\s*enum mixed_value_enum \{/) + }) + + it("should parse typedef declarations", () => { + // Anonymous struct typedefs + expect(parseResult).toMatch(/\d+--\d+ \|\s*typedef struct \{/) + + // Basic type typedefs + expect(parseResult).toMatch(/\d+--\d+ \|\s*typedef unsigned long long timestamp_typedef/) + + // Function pointer typedef usage + expect(parseResult).toMatch(/\d+--\d+ \|\s*extern TEST_COMPARE_FUNC test_get_comparator/) + }) + + it("should parse preprocessor definitions", () => { + // Object-like macros + expect(parseResult).toMatch(/\d+--\d+ \|\s*#define MAX_SIZE 1024/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*#define TEST_OS "windows"/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*#define TEST_OS "unix"/) + + // Function-like macros + expect(parseResult).toMatch(/\d+--\d+ \|\s*#define TEST_MIN\(a,b\)/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*#define TEST_MAX\(a,b\)/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*#define TEST_DEBUG_LOG\(level, msg, \.\.\.\)/) + + // Conditional compilation + expect(parseResult).toMatch(/\d+--\d+ \|\s*#ifdef _WIN32/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*#if TEST_DEBUG_LEVEL >= 2/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*#ifdef TEST_ENABLE_LOGGING/) + }) + + it("should parse global variable declarations", () => { + // Basic global variables + expect(parseResult).toMatch(/\d+--\d+ \|\s*static const int MAGIC_NUMBER =/) + + // Array variables + expect(parseResult).toMatch(/\d+--\d+ \|\s*static const char\* const BUILD_INFO\[\]/) + + // Struct variables + expect(parseResult).toMatch(/\d+--\d+ \|\s*static struct config_struct/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*\} DEFAULT_CONFIG =/) + }) +}) diff --git a/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.cpp.test.ts b/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.cpp.test.ts index 43c03a1ea53..15811c55ead 100644 --- a/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.cpp.test.ts +++ b/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.cpp.test.ts @@ -1,777 +1,112 @@ -import { describe, expect, it, jest, beforeEach } from "@jest/globals" - -import { cppQuery } from "../queries" -import { testParseSourceCodeDefinitions } from "./helpers" - -// Sample C++ content for tests covering all supported structures: -// - struct declarations -// - union declarations -// - function declarations -// - method declarations (with namespace scope) -// - typedef declarations -// - class declarations -// - enum declarations (including enum class) -// - namespace declarations (including nested namespaces) -// - template declarations (including specializations and variadic templates) -// - macro definitions -// - constructor declarations -// - destructor declarations -// - operator overloading -// - static member declarations -// - friend declarations -// - using declarations and directives -// - alias declarations (using) -// - constexpr functions and variables -// - lambda expressions -// - attributes -// - inheritance relationships -// - static variables -// - virtual functions -// - auto type deduction -// - concepts (C++20) -// - inline functions and variables -// - nested namespaces (C++17) -// - structured bindings (C++17) -// - noexcept specifier -// - default parameters -// - variadic templates -// - explicit template instantiation -const sampleCppContent = ` -// Basic struct declaration -struct Point { - double x; - double y; - - // Method within struct - double distanceFromOrigin() const { - return std::sqrt(x*x + y*y); - } -}; - -// Union declaration -union IntOrFloat { - int int_value; - float float_value; - - // Constructor for union - IntOrFloat() : int_value(0) {} -}; - -// Typedef declaration -typedef unsigned int uint; -typedef long double extended_precision; -typedef void (*FunctionPointer)(int, double); -typedef int IntArray[10]; - -// Class declaration -class Rectangle { -private: - double width; - double height; - -public: - // Constructor - Rectangle(double w, double h) : width(w), height(h) {} - - // Destructor - ~Rectangle() { - // Cleanup code here - width = 0; - height = 0; - } - - // Method declaration - double area() const { - return width * height; - } - - // Static member declaration - static Rectangle createSquare(double size) { - return Rectangle(size, size); - } - - // Operator overloading - bool operator==(const Rectangle& other) const { - return width == other.width && - height == other.height; - } - - // Friend declaration - friend std::ostream& operator<<(std::ostream& os, const Rectangle& rect); -}; - -// Standalone function declaration -double calculateDistance(const Point& p1, const Point& p2) { - double dx = p2.x - p1.x; - double dy = p2.y - p1.y; - return std::sqrt(dx * dx + dy * dy); -} - -// Namespace declaration -namespace geometry { - // Class in namespace - class Circle { - private: - double radius; - Point center; - - public: - Circle(double r, const Point& c) : radius(r), center(c) {} - - double area() const { - return 3.14159 * radius * radius; - } - - double circumference() const { - return 2 * 3.14159 * radius; - } - - // Virtual method - virtual void scale(double factor) { - radius *= factor; - } - }; - - // Function in namespace - double distanceFromOrigin(const Point& p) { - Point origin = {0.0, 0.0}; - return calculateDistance(origin, p); - } - - // Inline function - inline double square(double x) { - return x * x; - } - - // Inline variable (C++17) - inline constexpr double PI = 3.14159265358979323846; -} - -// Method declaration with namespace scope -double geometry::Circle::getRadius() const { - return radius; -} - -// Enum declaration -enum Color { - RED, - GREEN, - BLUE, - YELLOW -}; - -// Enum class (scoped enum) -enum class Direction { - NORTH, - SOUTH, - EAST, - WEST -}; - -// Template class declaration -template -class Container { -private: - T data; - -public: - Container(T value) : data(value) {} - - T getValue() const { - return data; - } - - void setValue(T value) { - data = value; - } -}; - -// Template function declaration -template -T max(T a, T b) { - return (a > b) ? a : b; -} - -// Using declaration -using std::string; -using std::vector; -using std::cout; -using std::endl; - -// Using directive -using namespace std; -using namespace geometry; -using namespace std::chrono; -using namespace std::literals; - -// Alias declaration (using) -using IntVector = std::vector; -using StringMap = std::map; -using IntFunction = int (*)(int, int); -using ComplexNumber = std::complex; - -// Constexpr function -constexpr int factorial(int n) { - return n <= 1 ? 1 : (n * factorial(n - 1)); -} - -// Constexpr variable -constexpr double PI = 3.14159265358979323846; -constexpr int MAX_BUFFER_SIZE = 1024; -constexpr char SEPARATOR = ';'; -constexpr bool DEBUG_MODE = true; - -// Lambda expression -auto multiplyBy = [](int x) { - return [x](int y) { - return x * y; - }; -}; - -// Lambda with capture -auto counter = [count = 0]() mutable { - return ++count; -}; - -// Attribute -[[nodiscard]] int importantFunction() { - return 42; -} - -// Multiple attributes -[[nodiscard, deprecated("Use newFunction instead")]] -int oldFunction() { - return 100; -} - -// Macro definition -#define SQUARE(x) ((x) * (x)) -#define MAX(a, b) ((a) > (b) ? (a) : (b)) -#define CONCAT(a, b) a##b -#define STR(x) #x - -// Inheritance -class Shape { -public: - virtual double area() const = 0; - virtual double perimeter() const = 0; - virtual ~Shape() {} - - // Static method in base class - static void printInfo() { - std::cout << "This is a shape." << std::endl; - } -}; - -class Square : public Shape { -private: - double side; - -public: - Square(double s) : side(s) {} - - double area() const override { - return side * side; - } - - double perimeter() const override { - return 4 * side; - } -}; - -// Multiple inheritance -class ColoredShape : public Shape { -protected: - Color color; - -public: - ColoredShape(Color c) : color(c) {} - - Color getColor() const { - return color; - } - - // Pure virtual method - virtual void render() const = 0; -}; - -class ColoredSquare : public Square, public ColoredShape { -public: - ColoredSquare(double s, Color c) : Square(s), ColoredShape(c) {} - - // Using declaration in class - using Square::area; - - void render() const override { - // Implementation here - std::cout << "Rendering colored square" << std::endl; - } -}; - -// Operator overloading as a non-member function -std::ostream& operator<<(std::ostream& os, const Rectangle& rect) { - os << "Rectangle(" << rect.width << ", " << rect.height << ")"; - return os; -} - -// Noexcept specifier -void safeFunction() noexcept { - // This function won't throw exceptions - int a = 5; - int b = 10; - int c = a + b; -} - -// Function with default parameters -void setValues(int a = 0, int b = 0, int c = 0) { - // Function with default parameters - int sum = a + b + c; - std::cout << "Sum: " << sum << std::endl; -} - -// Function with variadic templates -template -void printAll(Args... args) { - (std::cout << ... << args) << std::endl; -} - -// Variadic template with fold expressions (C++17) -template -auto sum(Args... args) { - return (... + args); -} - -// Structured binding (C++17) -void structuredBindingExample() { - std::pair person = {42, "John"}; - auto [id, name] = person; - - std::cout << "ID: " << id << ", Name: " << name << std::endl; -} - -// Auto type deduction -auto getNumber() { - return 42; -} - -auto getText() -> std::string { - return "Hello, World!"; -} - -// Inline namespace -inline namespace v1 { - void currentFunction() { - // Current version of the function - std::cout << "v1 implementation" << std::endl; - } -} - -// Nested namespace (C++17) -namespace graphics::rendering { - void render() { - // Rendering function - std::cout << "Rendering graphics" << std::endl; - } - - class Renderer { - public: - void draw() { - std::cout << "Drawing" << std::endl; - } - }; -} - -// Explicit template instantiation -template class Container; -template class Container; -template class Container; -template double max(double, double); - -// Static variable -static int globalCounter = 0; -static std::string appName = "CppApp"; -static const int VERSION_MAJOR = 1; -static const int VERSION_MINOR = 0; - -// Virtual inheritance to solve diamond problem -class Animal { -public: - virtual void speak() const { - std::cout << "Animal speaks" << std::endl; - } -}; - -class Mammal : virtual public Animal { -public: - void speak() const override { - std::cout << "Mammal speaks" << std::endl; - } -}; - -class Bird : virtual public Animal { -public: - void speak() const override { - std::cout << "Bird speaks" << std::endl; - } -}; - -class Bat : public Mammal, public Bird { -public: - void speak() const override { - std::cout << "Bat speaks" << std::endl; - } -}; - -// Concepts (C++20) - commented out for compatibility /* -template -concept Numeric = std::is_arithmetic_v; - -template -T add(T a, T b) { - return a + b; -} -*/ +TODO: The following C++ structures can be parsed by tree-sitter but lack query support: -// Class template with non-type parameters -template -class Array { -private: - T data[Size]; - -public: - Array() { - for (int i = 0; i < Size; ++i) { - data[i] = T(); - } - } - - T& operator[](int index) { - return data[index]; - } - - int size() const { - return Size; - } -}; +1. Virtual Methods: + (field_declaration (virtual) type: (primitive_type) declarator: (function_declarator)) + Example: virtual void method() = 0; -// Template specialization -template<> -class Container { -private: - bool data; - -public: - Container(bool value) : data(value) {} - - bool getValue() const { - return data; - } - - void setValue(bool value) { - data = value; - } - - void toggle() { - data = !data; - } -}; +2. Default Methods: + (default_method_clause) + Example: virtual ~base_class_definition() = default; -// Function with trailing return type -auto multiply(int a, int b) -> int { - return a * b; -} +3. Field Initializer Lists: + (field_initializer_list (field_initializer)) + Example: constructor() : field1(value1), field2(value2) {} -// Class with explicit constructors and conversion operators -class Number { -private: - int value; - -public: - explicit Number(int v) : value(v) {} - - explicit operator int() const { - return value; - } - - int getValue() const { - return value; - } -}; -` +4. Base Class Clauses: + (base_class_clause (access_specifier) (type_identifier)) + Example: class derived : public base {} -// C++ test options -const cppOptions = { - language: "cpp", - wasmFile: "tree-sitter-cpp.wasm", - queryString: cppQuery, - extKey: "cpp", - content: sampleCppContent, -} +5. Type Aliases: + (alias_declaration name: (type_identifier) type: (type_descriptor)) + Example: using size_type = std::size_t; +*/ -// Mock file system operations -jest.mock("fs/promises") +import { describe, it, expect, beforeAll } from "@jest/globals" +import { testParseSourceCodeDefinitions } from "./helpers" +import { cppQuery } from "../queries" +import sampleCppContent from "./fixtures/sample-cpp" -// Mock loadRequiredLanguageParsers -jest.mock("../languageParser", () => ({ - loadRequiredLanguageParsers: jest.fn(), -})) +describe("parseSourceCodeDefinitions (C++)", () => { + const testOptions = { + language: "cpp", + wasmFile: "tree-sitter-cpp.wasm", + queryString: cppQuery, + extKey: "cpp", + } -// Mock fileExistsAtPath to return true for our test paths -jest.mock("../../../utils/fs", () => ({ - fileExistsAtPath: jest.fn().mockImplementation(() => Promise.resolve(true)), -})) + let parseResult: string -describe("parseSourceCodeDefinitionsForFile with C++", () => { - beforeEach(() => { - jest.clearAllMocks() + beforeAll(async () => { + const result = await testParseSourceCodeDefinitions("test.cpp", sampleCppContent, testOptions) + expect(result).toBeDefined() + expect(typeof result).toBe("string") + expect(result).toContain("# test.cpp") + parseResult = result as string }) - it("should parse C++ struct declarations", async () => { - const result = await testParseSourceCodeDefinitions("/test/file.cpp", sampleCppContent, cppOptions) - - // Check for struct declarations - expect(result).toContain("struct Point") + it("should parse function declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \| void multiline_function_prototype\(/) + expect(parseResult).toMatch(/\d+--\d+ \| void function_with_implementation\(/) }) - it("should parse C++ union declarations", async () => { - const result = await testParseSourceCodeDefinitions("/test/file.cpp", sampleCppContent, cppOptions) - - // Check for union declarations - expect(result).toContain("union IntOrFloat") + it("should parse struct declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \| struct four_field_struct/) }) - it("should parse C++ function declarations", async () => { - const result = await testParseSourceCodeDefinitions("/test/file.cpp", sampleCppContent, cppOptions) - - // Check for function declarations - expect(result).toContain("double calculateDistance") + it("should parse class declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \| class base_class_definition/) + expect(parseResult).toMatch(/\d+--\d+ \| class template_class_definition/) }) - it("should parse C++ class declarations", async () => { - const result = await testParseSourceCodeDefinitions("/test/file.cpp", sampleCppContent, cppOptions) - - // Check for class declarations - expect(result).toContain("class Rectangle") + it("should parse union declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \| union four_member_union/) }) - it("should correctly identify structs, unions, and functions", async () => { - const result = await testParseSourceCodeDefinitions("/test/file.cpp", sampleCppContent, cppOptions) - - // Verify that structs, unions, and functions are being identified - const resultLines = result?.split("\n") || [] - - // Check that struct Point is found - const pointStructLine = resultLines.find((line) => line.includes("struct Point")) - expect(pointStructLine).toBeTruthy() - - // Check that union IntOrFloat is found - const unionLine = resultLines.find((line) => line.includes("union IntOrFloat")) - expect(unionLine).toBeTruthy() - - // Check that function calculateDistance is found - const distanceFuncLine = resultLines.find((line) => line.includes("double calculateDistance")) - expect(distanceFuncLine).toBeTruthy() + it("should parse enum declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \| enum class scoped_enumeration/) }) - it("should parse all basic C++ structures", async () => { - const result = await testParseSourceCodeDefinitions("/test/file.cpp", sampleCppContent, cppOptions) - const resultLines = result?.split("\n") || [] - - // Verify all struct declarations are captured - expect(resultLines.some((line) => line.includes("struct Point"))).toBe(true) - - // Verify union declarations are captured - expect(resultLines.some((line) => line.includes("union IntOrFloat"))).toBe(true) - // Verify typedef declarations are captured - not supported by current parser - // expect(resultLines.some((line) => line.includes("typedef unsigned int uint"))).toBe(true) - - // Verify class declarations are captured - expect(resultLines.some((line) => line.includes("class Rectangle"))).toBe(true) - - // Verify function declarations are captured - expect(resultLines.some((line) => line.includes("double calculateDistance"))).toBe(true) - - // Verify the output format includes line numbers - expect(resultLines.some((line) => /\d+--\d+ \|/.test(line))).toBe(true) - - // Verify the output includes the file name - expect(result).toContain("# file.cpp") + it("should parse typedef declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \| typedef std::vector { - const result = await testParseSourceCodeDefinitions("/test/file.cpp", sampleCppContent, cppOptions) - const resultLines = result?.split("\n") || [] - - // Test enum declarations - expect(resultLines.some((line) => line.includes("enum Color"))).toBe(true) - expect(resultLines.some((line) => line.includes("enum class Direction"))).toBe(true) - - // Test namespace declarations - expect(resultLines.some((line) => line.includes("namespace geometry"))).toBe(true) + it("should parse namespace declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \| namespace deeply_nested_namespace/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*namespace inner/) }) - it("should parse C++ templates", async () => { - const result = await testParseSourceCodeDefinitions("/test/file.cpp", sampleCppContent, cppOptions) - const resultLines = result?.split("\n") || [] - - // Test template class declarations - checking for template and class separately - expect(resultLines.some((line) => line.includes("template"))).toBe(true) - expect(resultLines.some((line) => line.includes("class Container"))).toBe(true) - - // Test template function declarations - not fully supported by current parser - // expect(resultLines.some((line) => line.includes("template") && line.includes("T max"))).toBe(true) - // Test template specialization - not supported by current parser - // expect(resultLines.some((line) => line.includes("template<>") && line.includes("class Container"))).toBe(true) - - // Test explicit template instantiation - not supported by current parser - // expect(resultLines.some((line) => line.includes("template class Container"))).toBe(true) + it("should parse template declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \| template { - const result = await testParseSourceCodeDefinitions("/test/file.cpp", sampleCppContent, cppOptions) - const resultLines = result?.split("\n") || [] - // Test constructor declarations - not supported by current parser - // expect(resultLines.some((line) => line.includes("Rectangle(double w, double h)"))).toBe(true) - - // Test destructor declarations - not supported by current parser - // expect(resultLines.some((line) => line.includes("~Rectangle()"))).toBe(true) - expect(resultLines.some((line) => line.includes("~Rectangle()"))).toBe(true) - - // Test operator overloading - expect(resultLines.some((line) => line.includes("operator=="))).toBe(true) - // Test static member declarations - not supported by current parser - // expect(resultLines.some((line) => line.includes("static Rectangle createSquare"))).toBe(true) - - // Test friend declarations - not supported by current parser - // expect(resultLines.some((line) => line.includes("friend std::ostream& operator<<"))).toBe(true) - }) - - it("should parse C++ using declarations and aliases", async () => { - // const result = await testParseSourceCodeDefinitions("/test/file.cpp", sampleCppContent, cppOptions) - // const resultLines = result?.split("\n") || [] - // Test using declarations - not supported by current parser - // expect(resultLines.some((line) => line.includes("using std::string"))).toBe(true) - // Test using directives - not supported by current parser - // expect(resultLines.some((line) => line.includes("using namespace std"))).toBe(true) - // Test alias declarations - not supported by current parser - // expect(resultLines.some((line) => line.includes("using IntVector = std::vector"))).toBe(true) - }) - - it("should parse C++ constexpr and lambda expressions", async () => { - const result = await testParseSourceCodeDefinitions("/test/file.cpp", sampleCppContent, cppOptions) - const resultLines = result?.split("\n") || [] - - // Test constexpr functions - not supported by current parser - // expect(resultLines.some((line) => line.includes("constexpr int factorial"))).toBe(true) - - // Test constexpr variables - not supported by current parser - // expect(resultLines.some((line) => line.includes("constexpr double PI"))).toBe(true) - - // Test lambda expressions - expect(resultLines.some((line) => line.includes("auto multiplyBy") || line.includes("lambda_expression"))).toBe( - true, - ) - }) - - it("should parse C++ attributes and macros", async () => { - // const result = await testParseSourceCodeDefinitions("/test/file.cpp", sampleCppContent, cppOptions) - // const resultLines = result?.split("\n") || [] - // Test attributes - not supported by current parser - // expect(resultLines.some((line) => line.includes("[[nodiscard]]") || line.includes("attribute_declaration"))).toBe(true) - // Test macro definitions - not supported by current parser - // expect(resultLines.some((line) => line.includes("#define SQUARE"))).toBe(true) - }) - - it("should parse C++ inheritance", async () => { - const result = await testParseSourceCodeDefinitions("/test/file.cpp", sampleCppContent, cppOptions) - const resultLines = result?.split("\n") || [] - - // Test inheritance - expect(resultLines.some((line) => line.includes("class Square : public Shape"))).toBe(true) - expect( - resultLines.some((line) => line.includes("class ColoredSquare : public Square, public ColoredShape")), - ).toBe(true) - }) - - it("should parse C++ virtual functions", async () => { - const result = await testParseSourceCodeDefinitions("/test/file.cpp", sampleCppContent, cppOptions) - const resultLines = result?.split("\n") || [] - - // Test virtual functions - checking for virtual keyword - expect(resultLines.some((line) => line.includes("virtual"))).toBe(true) + it("should parse macro definitions", () => { + expect(parseResult).toMatch(/\d+--\d+ \| #define MULTI_LINE_MACRO\(x, y\)/) }) - it("should parse C++ auto type deduction", async () => { - const result = await testParseSourceCodeDefinitions("/test/file.cpp", sampleCppContent, cppOptions) - const resultLines = result?.split("\n") || [] - - // Test auto type deduction - checking for auto keyword - expect(resultLines.some((line) => line.includes("auto"))).toBe(true) + it("should parse variable declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \| static const std::map { - // const result = await testParseSourceCodeDefinitions("/test/file.cpp", sampleCppContent, cppOptions) - // const resultLines = result?.split("\n") || [] - // Test inline functions - not supported by current parser - // expect(resultLines.some((line) => line.includes("inline double square"))).toBe(true) - // Test inline variables - not supported by current parser - // expect(resultLines.some((line) => line.includes("inline constexpr double PI"))).toBe(true) + it("should parse constructor declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*constructor_test\(/) }) - it("should parse C++17 features", async () => { - const result = await testParseSourceCodeDefinitions("/test/file.cpp", sampleCppContent, cppOptions) - const resultLines = result?.split("\n") || [] - - // Test nested namespaces (C++17) - expect(resultLines.some((line) => line.includes("namespace graphics::rendering"))).toBe(true) - - // Test structured bindings (C++17) - not supported by current parser - // expect(resultLines.some((line) => line.includes("auto [id, name] = person"))).toBe(true) - - // Test variadic templates with fold expressions (C++17) - not supported by current parser - // expect(resultLines.some((line) => line.includes("template") && line.includes("auto sum"))).toBe(true) + it("should parse destructor declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*~destructor_test\(\)/) }) - it("should parse C++ functions with special specifiers", async () => { - const result = await testParseSourceCodeDefinitions("/test/file.cpp", sampleCppContent, cppOptions) - const resultLines = result?.split("\n") || [] - - // Test noexcept specifier - expect(resultLines.some((line) => line.includes("void safeFunction() noexcept"))).toBe(true) - - // Test functions with default parameters - expect(resultLines.some((line) => line.includes("void setValues(int a = 0, int b = 0, int c = 0)"))).toBe(true) - - // Test functions with trailing return type - not supported by current parser - // expect(resultLines.some((line) => line.includes("auto multiply(int a, int b) -> int"))).toBe(true) + it("should parse operator overloads", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*bool operator==/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*bool operator { - const result = await testParseSourceCodeDefinitions("/test/file.cpp", sampleCppContent, cppOptions) - const resultLines = result?.split("\n") || [] - - // Test explicit constructors - not supported by current parser - // expect(resultLines.some((line) => line.includes("explicit Number(int v)"))).toBe(true) - - // Test conversion operators - not supported by current parser - // expect(resultLines.some((line) => line.includes("explicit operator int()"))).toBe(true) - - // Test virtual inheritance - expect(resultLines.some((line) => line.includes("class Mammal : virtual public Animal"))).toBe(true) + it("should parse friend declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*friend class friend_class;/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*friend void friend_function\(/) }) - it("should parse C++ template variations", async () => { - const result = await testParseSourceCodeDefinitions("/test/file.cpp", sampleCppContent, cppOptions) - const resultLines = result?.split("\n") || [] - - // Test class template with non-type parameters - checking for template and class separately - expect( - resultLines.some((line) => line.includes("template") || line.includes("template")), - ).toBe(true) - expect(resultLines.some((line) => line.includes("class Array"))).toBe(true) - - // Test variadic templates - not supported by current parser - // expect(resultLines.some((line) => line.includes("template") && line.includes("void printAll"))).toBe(true) + it("should parse using declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*using base_class_definition::virtual_method;/) }) }) diff --git a/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.css.test.ts b/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.css.test.ts new file mode 100644 index 00000000000..dc4857c57fa --- /dev/null +++ b/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.css.test.ts @@ -0,0 +1,71 @@ +import { describe, it, beforeAll, beforeEach } from "@jest/globals" +import { testParseSourceCodeDefinitions, debugLog } from "./helpers" +import { cssQuery } from "../queries" +import sampleCSSContent from "./fixtures/sample-css" + +describe("parseSourceCodeDefinitionsForFile with CSS", () => { + const testOptions = { + language: "css", + wasmFile: "tree-sitter-css.wasm", + queryString: cssQuery, + extKey: "css", + debug: true, + } + + let parseResult: string | undefined + + beforeAll(async () => { + // Cache parse result for all tests + parseResult = await testParseSourceCodeDefinitions("test.css", sampleCSSContent, testOptions) + if (!parseResult) { + throw new Error("No result returned from parser") + } + debugLog("CSS Parse Result:", parseResult) + }) + + beforeEach(() => { + jest.clearAllMocks() + }) + + it("should parse CSS variable declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*--test-variable-definition-primary:/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*--test-variable-definition-secondary:/) + debugLog("Variable declarations:", parseResult!.match(/--test-variable-definition-[\w-]+:[\s\S]*?;/g)) + }) + + it("should parse import statements", () => { + expect(parseResult).toMatch(/\d+--\d+ \| @import .+test-import-definition/) + debugLog("Import statements:", parseResult!.match(/@import[\s\S]*?;/g)) + }) + + it("should parse media queries", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*\.test-media-query-definition/) + debugLog("Media queries:", parseResult!.match(/@media[\s\S]*?{[\s\S]*?}/g)) + }) + + it("should parse keyframe declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \| @keyframes test-keyframe-definition-fade/) + debugLog("Keyframe declarations:", parseResult!.match(/@keyframes[\s\S]*?{[\s\S]*?}/g)) + }) + + it("should parse function declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \| {1,}background-color: rgba\(/) + expect(parseResult).toMatch(/\d+--\d+ \| {1,}transform: translate\(/) + debugLog("Function declarations:", parseResult!.match(/(?:rgba|translate|calc|var)\([\s\S]*?\)/g)) + }) + + it("should parse basic rulesets", () => { + expect(parseResult).toMatch(/\d+--\d+ \| \.test-ruleset-definition {/) + debugLog("Basic rulesets:", parseResult!.match(/\.test-ruleset-definition[\s\S]*?{[\s\S]*?}/g)) + }) + + it("should parse complex selectors", () => { + expect(parseResult).toMatch(/\d+--\d+ \| \.test-selector-definition[:\s>]/) + debugLog("Complex selectors:", parseResult!.match(/\.test-selector-definition[\s\S]*?{[\s\S]*?}/g)) + }) + + it("should parse nested rulesets", () => { + expect(parseResult).toMatch(/\d+--\d+ \| \.test-nested-ruleset-definition {/) + debugLog("Nested rulesets:", parseResult!.match(/\.test-nested-ruleset-definition[\s\S]*?{[\s\S]*?}/g)) + }) +}) diff --git a/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.elisp.test.ts b/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.elisp.test.ts new file mode 100644 index 00000000000..196d8383945 --- /dev/null +++ b/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.elisp.test.ts @@ -0,0 +1,67 @@ +/* +TODO: The following structures can be parsed by tree-sitter but lack query support: + +1. Variable Definition: + (defvar name value docstring) + +2. Constant Definition: + (defconst name value docstring) +*/ + +import { describe, it, expect } from "@jest/globals" +import { testParseSourceCodeDefinitions } from "./helpers" +import { elispQuery } from "../queries/elisp" +import sampleElispContent from "./fixtures/sample-elisp" + +describe("parseSourceCodeDefinitions.elisp", () => { + const testOptions = { + language: "elisp", + wasmFile: "tree-sitter-elisp.wasm", + queryString: elispQuery, + extKey: "el", + } + + let parseResult: string = "" + + beforeAll(async () => { + const result = await testParseSourceCodeDefinitions("file.el", sampleElispContent, testOptions) + expect(result).toBeDefined() + if (!result) { + throw new Error("Failed to parse source code definitions") + } + parseResult = result + }) + + it("should parse function definitions", () => { + expect(parseResult).toMatch(/\d+--\d+ \| \(defun test-function/) + }) + + it("should parse macro definitions", () => { + expect(parseResult).toMatch(/\d+--\d+ \| \(defmacro test-macro/) + }) + + it("should parse custom form definitions", () => { + expect(parseResult).toMatch(/\d+--\d+ \| \(defcustom test-custom/) + }) + + it("should parse face definitions", () => { + expect(parseResult).toMatch(/\d+--\d+ \| \(defface test-face/) + }) + + it("should parse advice definitions", () => { + expect(parseResult).toMatch(/\d+--\d+ \| \(defadvice test-advice/) + }) + + it("should parse group definitions", () => { + expect(parseResult).toMatch(/\d+--\d+ \| \(defgroup test-group nil/) + }) + + it("should verify total number of definitions", () => { + const matches = parseResult.match(/\d+--\d+ \|/g) || [] + expect(matches.length).toBe(6) // All supported definition types + }) + + it("should verify file header is present", () => { + expect(parseResult).toMatch(/# file\.el/) + }) +}) diff --git a/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.elixir.test.ts b/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.elixir.test.ts new file mode 100644 index 00000000000..d16dcb062af --- /dev/null +++ b/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.elixir.test.ts @@ -0,0 +1,90 @@ +import { describe, expect, it, jest, beforeAll, beforeEach } from "@jest/globals" +import { elixirQuery } from "../queries" +import { testParseSourceCodeDefinitions, debugLog } from "./helpers" +import sampleElixirContent from "./fixtures/sample-elixir" + +// Elixir test options +const elixirOptions = { + language: "elixir", + wasmFile: "tree-sitter-elixir.wasm", + queryString: elixirQuery, + extKey: "ex", +} + +// Mock file system operations +jest.mock("fs/promises") + +// Mock loadRequiredLanguageParsers +jest.mock("../languageParser", () => ({ + loadRequiredLanguageParsers: jest.fn(), +})) + +// Mock fileExistsAtPath to return true for our test paths +jest.mock("../../../utils/fs", () => ({ + fileExistsAtPath: jest.fn().mockImplementation(() => Promise.resolve(true)), +})) + +describe("parseSourceCodeDefinitionsForFile with Elixir", () => { + let parseResult: string = "" + + beforeAll(async () => { + // Cache parse result for all tests + parseResult = (await testParseSourceCodeDefinitions("/test/file.ex", sampleElixirContent, elixirOptions))! + debugLog("Elixir Parse Result:", parseResult) + }) + + beforeEach(() => { + jest.clearAllMocks() + }) + + it("should parse module definitions", () => { + expect(parseResult).toMatch(/\d+--\d+ \| defmodule TestModuleDefinition do/) + expect(parseResult).toMatch(/\d+--\d+ \| defmodule TestBehaviourDefinition do/) + expect(parseResult).toMatch(/\d+--\d+ \| defmodule TestModuleDefinitionTest do/) + debugLog("Module definitions found:", parseResult.match(/defmodule[\s\S]*?end/g)) + }) + + it("should parse function definitions", () => { + expect(parseResult).toMatch(/\d+--\d+ \| def test_function_definition/) + expect(parseResult).toMatch(/\d+--\d+ \| def test_pipeline_definition/) + expect(parseResult).toMatch(/\d+--\d+ \| def test_comprehension_definition/) + expect(parseResult).toMatch(/\d+--\d+ \| def test_sigil_definition/) + debugLog("Function definitions found:", parseResult.match(/def[\s\S]*?end/g)) + }) + + it("should parse macro definitions", () => { + expect(parseResult).toMatch(/\d+--\d+ \| defmacro test_macro_definition/) + debugLog("Macro definitions found:", parseResult.match(/defmacro[\s\S]*?end/g)) + }) + + it("should parse protocol implementations", () => { + expect(parseResult).toMatch(/\d+--\d+ \| defimpl String\.Chars/) + debugLog("Protocol implementations found:", parseResult.match(/defimpl[\s\S]*?end/g)) + }) + + it("should parse behaviour callbacks", () => { + expect(parseResult).toMatch(/\d+--\d+ \| @callback test_behaviour_callback/) + debugLog("Behaviour callbacks found:", parseResult.match(/@callback[\s\S]*?\)/g)) + }) + + it("should parse struct definitions", () => { + expect(parseResult).toMatch(/\d+--\d+ \| defstruct \[/) + debugLog("Struct definitions found:", parseResult.match(/defstruct[\s\S]*?\]/g)) + }) + + it("should parse guard definitions", () => { + expect(parseResult).toMatch(/\d+--\d+ \| defguard test_guard_definition/) + debugLog("Guard definitions found:", parseResult.match(/defguard[\s\S]*?end/g)) + }) + + it("should parse module attributes", () => { + expect(parseResult).toMatch(/\d+--\d+ \| @test_attribute_definition/) + expect(parseResult).toMatch(/\d+--\d+ \| @moduledoc/) + debugLog("Module attributes found:", parseResult.match(/@[\s\S]*?\]/g)) + }) + + it("should parse test definitions", () => { + expect(parseResult).toMatch(/\d+--\d+ \| test "test_definition"/) + debugLog("Test definitions found:", parseResult.match(/test[\s\S]*?end/g)) + }) +}) diff --git a/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.embedded_template.test.ts b/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.embedded_template.test.ts new file mode 100644 index 00000000000..523907923c9 --- /dev/null +++ b/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.embedded_template.test.ts @@ -0,0 +1,53 @@ +import { describe, it } from "@jest/globals" +import { debugLog, testParseSourceCodeDefinitions } from "./helpers" +import { embeddedTemplateQuery } from "../queries" +import sampleEmbeddedTemplateContent from "./fixtures/sample-embedded_template" + +describe("parseSourceCodeDefinitions (Embedded Template)", () => { + const testOptions = { + language: "embedded_template", + wasmFile: "tree-sitter-embedded_template.wasm", + queryString: embeddedTemplateQuery, + extKey: "erb", + minComponentLines: 4, + } + + let parseResult: string = "" + + beforeAll(async () => { + const result = await testParseSourceCodeDefinitions("test.erb", sampleEmbeddedTemplateContent, testOptions) + if (!result) { + throw new Error("Failed to parse source code definitions") + } + parseResult = result + debugLog("All definitions:", parseResult) + }) + + it("should detect multi-line comments", () => { + expect(parseResult).toMatch(/\d+--\d+ \| <%# Multi-line comment block explaining/) + }) + + it("should detect function definitions", () => { + expect(parseResult).toMatch(/\d+--\d+ \| <% def complex_helper\(param1, param2\)/) + expect(parseResult).toMatch(/\d+--\d+ \| <% def render_navigation\(items\)/) + }) + + it("should detect class definitions", () => { + expect(parseResult).toMatch(/\d+--\d+ \| <% class TemplateHelper/) + }) + + it("should detect module definitions", () => { + expect(parseResult).toMatch(/\d+--\d+ \| <% module TemplateUtils/) + }) + + it("should detect control structures", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s+<% if user\.authenticated\? %>/) + expect(parseResult).toMatch(/\d+--\d+ \|\s+<% user\.posts\.each do \|post\| %>/) + expect(parseResult).toMatch(/\d+--\d+ \|\s+<% if post\.has_comments\? %>/) + }) + + it("should detect content blocks", () => { + expect(parseResult).toMatch(/\d+--\d+ \| <% content_for :header do/) + expect(parseResult).toMatch(/\d+--\d+ \| <% content_for :main do/) + }) +}) diff --git a/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.go.test.ts b/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.go.test.ts index 137809626d8..57fc8041353 100644 --- a/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.go.test.ts +++ b/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.go.test.ts @@ -1,391 +1,96 @@ -import { describe, expect, it, jest, beforeEach } from "@jest/globals" - -import { goQuery } from "../queries" +/* +TODO: The following structures can be parsed by tree-sitter but lack query support: + +1. Anonymous Functions (func_literal): + (func_literal parameters: (parameter_list) body: (block ...)) + - Currently visible in goroutine and defer statements + - Would enable capturing lambda/closure definitions + +2. Map Types (map_type): + (map_type key: (type_identifier) value: (interface_type)) + - Currently visible in struct field declarations + - Would enable capturing map type definitions + +3. Pointer Types (pointer_type): + (pointer_type (type_identifier)) + - Currently visible in method receiver declarations + - Would enable capturing pointer type definitions +*/ + +import { describe, it, expect, beforeAll } from "@jest/globals" +import sampleGoContent from "./fixtures/sample-go" import { testParseSourceCodeDefinitions } from "./helpers" - -// Sample Go content for tests covering all supported structures: -// - function declarations (with associated comments) -// - method declarations (with associated comments) -// - type specifications -// - struct definitions -// - interface definitions -// - constant declarations -// - variable declarations -// - type aliases -// - embedded structs -// - embedded interfaces -// - init functions -// - anonymous functions -// - generic types (Go 1.18+) -// - package-level variables -// - multiple constants in a single block -// - multiple variables in a single block -const sampleGoContent = ` -package main - -import ( - "fmt" - "math" - "strings" -) - -// Basic struct definition -// This is a simple Point struct -type Point struct { - X float64 - Y float64 -} - -// Method for Point struct -// Calculates the distance from the origin -func (p Point) DistanceFromOrigin() float64 { - return math.Sqrt(p.X*p.X + p.Y*p.Y) -} - -// Another method for Point struct -// Moves the point by the given deltas -func (p *Point) Move(dx, dy float64) { - p.X += dx - p.Y += dy -} - -// Basic interface definition -// Defines a shape with area and perimeter methods -type Shape interface { - Area() float64 - Perimeter() float64 -} - -// Rectangle struct implementing Shape interface -type Rectangle struct { - Width float64 - Height float64 -} - -// Area method for Rectangle -func (r Rectangle) Area() float64 { - return r.Width * r.Height -} - -// Perimeter method for Rectangle -func (r Rectangle) Perimeter() float64 { - return 2 * (r.Width + r.Height) -} - -// Circle struct implementing Shape interface -type Circle struct { - Radius float64 -} - -// Area method for Circle -func (c Circle) Area() float64 { - return math.Pi * c.Radius * c.Radius -} - -// Perimeter method for Circle -func (c Circle) Perimeter() float64 { - return 2 * math.Pi * c.Radius -} - -// Constants declaration -const ( - Pi = 3.14159 - MaxItems = 100 - DefaultName = "Unknown" -) - -// Single constant declaration -const AppVersion = "1.0.0" - -// Variables declaration -var ( - MaxConnections = 1000 - Timeout = 30 - IsDebug = false -) - -// Single variable declaration -var GlobalCounter int = 0 - -// Type alias -type Distance float64 - -// Function with multiple parameters -func CalculateDistance(p1, p2 Point) Distance { - dx := p2.X - p1.X - dy := p2.Y - p1.Y - return Distance(math.Sqrt(dx*dx + dy*dy)) -} - -// Function with a comment -// This function formats a name -func FormatName(first, last string) string { - return fmt.Sprintf("%s, %s", last, first) -} - -// Struct with embedded struct -type Employee struct { - Person // Embedded struct - JobTitle string - Salary float64 -} - -// Person struct to be embedded -type Person struct { - FirstName string - LastName string - Age int -} - -// Interface with embedded interface -type ReadWriter interface { - Reader // Embedded interface - Writer // Embedded interface - ReadAndWrite() bool -} - -// Reader interface to be embedded -type Reader interface { - Read() []byte -} - -// Writer interface to be embedded -type Writer interface { - Write(data []byte) int -} - -// Init function -func init() { - fmt.Println("Initializing package...") - GlobalCounter = 1 -} - -// Function that returns an anonymous function -func CreateCounter() func() int { - count := 0 - - // Anonymous function - return func() int { - count++ - return count - } -} - -// Generic type (Go 1.18+) -type Stack[T any] struct { - items []T -} - -// Generic method for Stack -func (s *Stack[T]) Push(item T) { - s.items = append(s.items, item) -} - -// Generic method for Stack -func (s *Stack[T]) Pop() (T, bool) { - var zero T - if len(s.items) == 0 { - return zero, false - } - - item := s.items[len(s.items)-1] - s.items = s.items[:len(s.items)-1] - return item, true -} - -// Generic function (Go 1.18+) -func Map[T, U any](items []T, f func(T) U) []U { - result := make([]U, len(items)) - for i, item := range items { - result[i] = f(item) - } - return result -} - -// Function that uses an anonymous function -func ProcessItems(items []string) []string { - return Map(items, func(s string) string { - return strings.ToUpper(s) - }) -} - -// Main function -func main() { - fmt.Println("Hello, World!") - - // Using structs - p := Point{X: 3, Y: 4} - fmt.Printf("Distance from origin: %f\n", p.DistanceFromOrigin()) - - // Using interfaces - var shapes []Shape = []Shape{ - Rectangle{Width: 5, Height: 10}, - Circle{Radius: 7}, - } - - for _, shape := range shapes { - fmt.Printf("Area: %f, Perimeter: %f\n", shape.Area(), shape.Perimeter()) - } - - // Using anonymous function - counter := CreateCounter() - fmt.Println(counter()) // 1 - fmt.Println(counter()) // 2 - - // Using generic types - stack := Stack[int]{} - stack.Push(1) - stack.Push(2) - stack.Push(3) - - if val, ok := stack.Pop(); ok { - fmt.Println(val) // 3 - } -} -` - -// Go test options -const goOptions = { - language: "go", - wasmFile: "tree-sitter-go.wasm", - queryString: goQuery, - extKey: "go", - content: sampleGoContent, -} - -// Mock file system operations -jest.mock("fs/promises") - -// Mock loadRequiredLanguageParsers -jest.mock("../languageParser", () => ({ - loadRequiredLanguageParsers: jest.fn(), -})) - -// Mock fileExistsAtPath to return true for our test paths -jest.mock("../../../utils/fs", () => ({ - fileExistsAtPath: jest.fn().mockImplementation(() => Promise.resolve(true)), -})) - -describe("parseSourceCodeDefinitionsForFile with Go", () => { - beforeEach(() => { - jest.clearAllMocks() +import goQuery from "../queries/go" + +describe("Go Source Code Definition Tests", () => { + let parseResult: string + + beforeAll(async () => { + const testOptions = { + language: "go", + wasmFile: "tree-sitter-go.wasm", + queryString: goQuery, + extKey: "go", + } + + const result = await testParseSourceCodeDefinitions("file.go", sampleGoContent, testOptions) + expect(result).toBeDefined() + parseResult = result as string }) - it("should parse Go struct definitions", async () => { - const result = await testParseSourceCodeDefinitions("/test/file.go", sampleGoContent, goOptions) - - // Check for struct definitions - we only check for the ones that are actually captured - expect(result).toContain("type Point struct") - expect(result).toContain("type Rectangle struct") - // Note: Some structs might not be captured due to Tree-Sitter parser limitations + it("should parse package declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*package main/) }) - it("should parse Go method declarations", async () => { - const result = await testParseSourceCodeDefinitions("/test/file.go", sampleGoContent, goOptions) - - // Check for method declarations - we only check for the ones that are actually captured - expect(result).toContain("func (p *Point) Move") - // Note: Some methods might not be captured due to Tree-Sitter parser limitations + it("should parse import declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*"fmt"/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*"sync"/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*"time"/) }) - it("should parse Go function declarations", async () => { - const result = await testParseSourceCodeDefinitions("/test/file.go", sampleGoContent, goOptions) - - // Check for function declarations - we only check for the ones that are actually captured - expect(result).toContain("func CalculateDistance") - expect(result).toContain("func CreateCounter") - // Note: Some functions might not be captured due to Tree-Sitter parser limitations + it("should parse const declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*TestConstDefinition1 = "test1"/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*TestConstDefinition2 = "test2"/) }) - it("should parse Go interface definitions", async () => { - const result = await testParseSourceCodeDefinitions("/test/file.go", sampleGoContent, goOptions) - - // Check for interface definitions - we only check for the ones that are actually captured - expect(result).toContain("type Shape interface") - expect(result).toContain("type ReadWriter interface") - // Note: Some interfaces might not be captured due to Tree-Sitter parser limitations + it("should parse var declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*TestVarDefinition1 string = "var1"/) + expect(parseResult).toMatch(/\d+--\d+ \|\s*TestVarDefinition2 int\s*= 42/) }) - it("should parse Go constant and variable declarations", async () => { - const result = await testParseSourceCodeDefinitions("/test/file.go", sampleGoContent, goOptions) - const resultLines = result?.split("\n") || [] - - // Check for constant and variable groups - expect(resultLines.some((line) => line.includes("const ("))).toBe(true) - expect(resultLines.some((line) => line.includes("var ("))).toBe(true) - // Note: Individual constants/variables might not be captured due to Tree-Sitter parser limitations + it("should parse interface declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*type TestInterfaceDefinition interface/) }) - it("should parse Go type aliases", async () => { - await testParseSourceCodeDefinitions("/test/file.go", sampleGoContent, goOptions) - - // Note: Type aliases might not be captured due to Tree-Sitter parser limitations - // This test is kept for completeness - expect(true).toBe(true) + it("should parse struct declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*type TestStructDefinition struct/) }) - it("should parse Go embedded structs and interfaces", async () => { - await testParseSourceCodeDefinitions("/test/file.go", sampleGoContent, goOptions) - // Note: Embedded structs and interfaces might not be captured due to Tree-Sitter parser limitations - // This test is kept for completeness - expect(true).toBe(true) + it("should parse type declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*type TestTypeDefinition struct/) }) - it("should parse Go init functions", async () => { - const result = await testParseSourceCodeDefinitions("/test/file.go", sampleGoContent, goOptions) - - // Check for init functions - expect(result).toContain("func init") + it("should parse function declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*func TestFunctionDefinition\(/) }) - it("should parse Go anonymous functions", async () => { - const result = await testParseSourceCodeDefinitions("/test/file.go", sampleGoContent, goOptions) - const resultLines = result?.split("\n") || [] - - // Check for anonymous functions - we look for the return statement that contains the anonymous function - expect(resultLines.some((line) => line.includes("return func"))).toBe(true) + it("should parse method declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*func \(t \*TestStructDefinition\) TestMethodDefinition\(/) }) - it("should parse Go generic types and functions", async () => { - const result = await testParseSourceCodeDefinitions("/test/file.go", sampleGoContent, goOptions) - const resultLines = result?.split("\n") || [] - - // Check for generic functions - we only check for the ones that are actually captured - expect(resultLines.some((line) => line.includes("func Map[T, U any]"))).toBe(true) - expect(resultLines.some((line) => line.includes("func (s *Stack[T])"))).toBe(true) - // Note: Generic types might not be captured due to Tree-Sitter parser limitations + it("should parse channel function declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*func TestChannelDefinition\(/) }) - it("should handle all Go language constructs comprehensively", async () => { - const result = await testParseSourceCodeDefinitions("/test/file.go", sampleGoContent, goOptions) - const resultLines = result?.split("\n") || [] - - // Verify struct definitions are captured - expect(resultLines.some((line) => line.includes("type Point struct"))).toBe(true) - expect(resultLines.some((line) => line.includes("type Rectangle struct"))).toBe(true) - expect(resultLines.some((line) => line.includes("type Employee struct"))).toBe(true) - expect(resultLines.some((line) => line.includes("type Person struct"))).toBe(true) - - // Verify interface definitions are captured - expect(resultLines.some((line) => line.includes("type Shape interface"))).toBe(true) - expect(resultLines.some((line) => line.includes("type ReadWriter interface"))).toBe(true) - - // Verify method declarations are captured - expect(resultLines.some((line) => line.includes("func (p *Point) Move"))).toBe(true) - - // Verify function declarations are captured - expect(resultLines.some((line) => line.includes("func CalculateDistance"))).toBe(true) - expect(resultLines.some((line) => line.includes("func CreateCounter"))).toBe(true) - expect(resultLines.some((line) => line.includes("func init"))).toBe(true) - - // Verify constant and variable groups are captured - expect(resultLines.some((line) => line.includes("const ("))).toBe(true) - expect(resultLines.some((line) => line.includes("var ("))).toBe(true) + it("should parse goroutine function declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*func TestGoroutineDefinition\(\)/) + }) - // Verify the output format includes line numbers - expect(resultLines.some((line) => /\d+--\d+ \|/.test(line))).toBe(true) + it("should parse defer function declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*func TestDeferDefinition\(\)/) + }) - // Verify the output includes the file name - expect(result).toContain("# file.go") + it("should parse select function declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*func TestSelectDefinition\(/) }) }) diff --git a/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.html.test.ts b/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.html.test.ts new file mode 100644 index 00000000000..1ac6d55024d --- /dev/null +++ b/src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.html.test.ts @@ -0,0 +1,70 @@ +import { describe, it, expect } from "@jest/globals" +import { sampleHtmlContent } from "./fixtures/sample-html" +import { htmlQuery } from "../queries" +import { testParseSourceCodeDefinitions } from "./helpers" + +describe("HTML Source Code Definition Tests", () => { + let parseResult: string + + beforeAll(async () => { + const testOptions = { + language: "html", + wasmFile: "tree-sitter-html.wasm", + queryString: htmlQuery, + extKey: "html", + } + const result = await testParseSourceCodeDefinitions("test.html", sampleHtmlContent, testOptions) + if (!result) { + throw new Error("Failed to parse HTML content") + } + parseResult = result + }) + + it("should parse doctype definition", () => { + expect(parseResult).toMatch(/1--1 \|\s*/) + }) + + it("should parse document definition", () => { + expect(parseResult).toMatch(/2--2 \|\s*/) + }) + + it("should parse element definition", () => { + expect(parseResult).toMatch(/17--17 \|\s*
{ + expect(parseResult).toMatch(/32--32 \|\s*