From 8e85a121f1f2272dd5266ee59def0c994e5697d8 Mon Sep 17 00:00:00 2001 From: KJ7LNW <93454819+KJ7LNW@users.noreply.github.com> Date: Mon, 28 Apr 2025 08:27:49 -0700 Subject: [PATCH] feat: standardize tree-sitter test implementations (#2960) * refactor: standardize C# Tree-Sitter parser tests This commit standardizes the C# Tree-Sitter parser tests to ensure: - Variable/function names in sample code match the tests - Each test only verifies specific identifiers relevant to that test - Test names clearly indicate what they're testing - No skipped tests remain - Only one test exists per structure or combination of structures - All debug output uses debugLog from helpers.ts The standardization improves maintainability and clarity while preserving all existing functionality. Signed-off-by: Eric Wheeler * refactor: standardize C Tree-Sitter parser tests This commit standardizes the C Tree-Sitter parser tests to ensure: - Variable/function names in sample code match the tests (using snake_case) - Each test only verifies specific identifiers relevant to that test - Test names clearly indicate what they're testing - No skipped tests remain - tests for unsupported features are removed - Only one test exists per structure or combination of structures - All debug output uses debugLog from helpers.ts The standardization improves maintainability and clarity while preserving all existing functionality. Documentation has been added for C language constructs that are not currently supported by the parser. Signed-off-by: Eric Wheeler * feat: standardize Kotlin Tree-Sitter parser Standardized Kotlin Tree-Sitter parser to ensure consistent naming and structure: - Renamed identifiers to clearly indicate what they're testing - Ensured all code sections are at least 4 lines long - Organized query patterns logically with clear comments - Removed skipped tests and unused query patterns - Ensured only one test per structure or combination of structures Signed-off-by: Eric Wheeler * feat: standardize PHP Tree-Sitter parser Standardized PHP Tree-Sitter parser to ensure consistent naming and structure: - Renamed identifiers to clearly indicate what they're testing - Ensured all code sections are at least 4 lines long - Organized query patterns logically with clear comments - Consolidated related tests to ensure only one test per structure - Ensured all debug output uses debugLog from helpers.ts Signed-off-by: Eric Wheeler * feat: standardize Ruby Tree-Sitter parser Standardized Ruby Tree-Sitter parser to ensure consistent naming and structure: - Expanded query to support many more Ruby language constructs - Added comprehensive test file with clear section headers - Ensured all code sections are at least 4 lines long - Added tests for each language construct - Used consistent naming conventions for test identifiers Signed-off-by: Eric Wheeler * feat: standardize Swift Tree-Sitter parser Standardized Swift Tree-Sitter parser to ensure consistent naming and structure: - Renamed identifiers to clearly indicate what they're testing - Ensured all code sections are at least 4 lines long - Organized query patterns logically with clear comments - Removed skipped tests and unused query patterns - Ensured only one test per structure or combination of structures Signed-off-by: Eric Wheeler * feat: dynamically include all tree-sitter WASM files in build process - Modified esbuild.js to dynamically read and copy all WASM files from tree-sitter-wasms package - Added error handling and logging for better debugging - Ensures all language parsers are automatically included without requiring manual updates * refactor: move test mocks and fixtures to shared locations Move test mocks to helpers.ts to be shared between test files Create fixtures directory for shared test data Move sample TSX content to fixtures/sample-tsx.ts Update test files to use shared mocks and fixtures Signed-off-by: Eric Wheeler * refactor: simplify tree-sitter debug output - Remove detailed node inspection to reduce noise - Keep only essential tree structure output - Remove duplicate content logging Signed-off-by: Eric Wheeler * refactor: standardize C# tree-sitter test structure Move C# sample code to dedicated fixture file and create inspectCSharp test following the same pattern as other language tests. This improves test organization and maintainability by: - Extracting sample C# code to fixtures/sample-c-sharp.ts - Adding inspectCSharp.test.ts for tree structure inspection - Updating parseSourceCodeDefinitions.c-sharp.test.ts to use fixture Signed-off-by: Eric Wheeler * feat: add language-specific capture processing - Add language parameter to processCaptures for language-specific handling - Implement selective HTML filtering for jsx/tsx files - Update all call sites to pass correct language parameter - Fix type safety by properly passing language strings Signed-off-by: Eric Wheeler * refactor: move tree-sitter test samples to fixtures Move sample code from parseSourceCodeDefinitions test files into dedicated fixtures directory for better organization and reuse: - Created fixtures directory for language samples - Moved sample code for C#, C, JSON, Kotlin, PHP, Ruby, Rust, and Swift - Created inspect test files for each language - Updated original test files to import from fixtures - Standardized test options across languages - No behavior changes, all tests passing Signed-off-by: Eric Wheeler * refactor: standardize tree-sitter test code across languages Standardize test code structure and naming across all language parsers: - Rename identifiers to clearly indicate test purpose - Ensure each code section has descriptive comments - Group related code sections together - Maintain language-specific naming conventions - Keep test structure consistent across languages - Remove tests for unsupported features Changes made to: - C, JSON, Kotlin, PHP, Ruby, Rust, and Swift test files - Sample code fixtures - Parser definition tests - Inspect structure tests No functional changes - all tests passing with improved maintainability. Signed-off-by: Eric Wheeler * refactor: standardize tree-sitter parser tests across all languages - Ensure all test structures span at least 4 lines for better parsing - Create exactly one consolidated test per data structure type - Use descriptive names that clearly indicate test purpose - Improve query pattern organization and documentation - Simplify inspect test files to focus on structure validation - Implement result caching in test files for better performance - Remove duplicate and skipped tests - Follow consistent naming conventions across all languages Signed-off-by: Eric Wheeler * first pass all but elm-bash * test: inspectTreeStructure helper now returns a string Signed-off-by: Eric Wheeler * refactor: establish single source of truth for MIN_COMPONENT_LINES - Move minComponentLines parameter to a file-level constant - Remove parameter passing to processCaptures function - Update all references to use the global constant - Remove redundant local constant declaration in parseFile Signed-off-by: Eric Wheeler * refactor: improve MIN_COMPONENT_LINES implementation - Changed MIN_COMPONENT_LINES constant to use getter/setter functions - Updated references to use getMinComponentLines() function - Modified test helper to set value to 0 during tests - This establishes a single source of truth while making testing easier Signed-off-by: Eric Wheeler * feat: standardize tree-sitter test implementations Standardized tree-sitter test implementations across all supported languages: - Removed debugLog calls from test files - Implemented consistent line number pattern matching - Ensured proper test structure and execution order - Added comprehensive test coverage for supported structures - Maintained 1:1 mapping between queries, tests and samples - Documented unsupported features in TODO sections Signed-off-by: Eric Wheeler * docs: document tree-sitter parseable but unsupported structures Added TODO sections in test files documenting structures that can be parsed by tree-sitter but currently lack query pattern support: - Python: f-strings, complex type annotations, pattern matching - C++: virtual methods, field initializers, base class clauses - Java: import declarations, field declarations with modifiers - TSX: React hooks, context providers, event handlers Added examples and clarifying comments to existing TODO sections. Enhanced Java query patterns for better structure capture including lambda expressions, field declarations, and type parameters. Signed-off-by: Eric Wheeler * fix: use correct distDir variable for WASM file copying The copyWasmFiles plugin was using an undefined targetDir variable when copying tree-sitter WASM files. Changed to use the correctly defined distDir variable, fixing the build process. Signed-off-by: Eric Wheeler * lint: remove unused imports and variables from tree-sitter tests Removed unused imports and variables from tree-sitter test files to fix linting errors: - Removed unused goQuery import from helpers.ts - Removed unused imports and mockedFs variables from language-specific test files - Cleaned up test files to only import what they use Signed-off-by: Eric Wheeler --------- Signed-off-by: Eric Wheeler Co-authored-by: Eric Wheeler --- esbuild.js | 40 +- .../__tests__/fixtures/sample-c-sharp.ts | 390 +++++++ .../__tests__/fixtures/sample-c.ts | 453 ++++++++ .../__tests__/fixtures/sample-cpp.ts | 179 +++ .../__tests__/fixtures/sample-css.ts | 97 ++ .../__tests__/fixtures/sample-elisp.ts | 56 + .../__tests__/fixtures/sample-elixir.ts | 117 ++ .../fixtures/sample-embedded_template.ts | 88 ++ .../__tests__/fixtures/sample-go.ts | 126 +++ .../__tests__/fixtures/sample-html.ts | 88 ++ .../__tests__/fixtures/sample-java.ts | 193 ++++ .../__tests__/fixtures/sample-javascript.ts | 165 +++ .../__tests__/fixtures/sample-json.ts | 108 ++ .../__tests__/fixtures/sample-kotlin.ts | 403 +++++++ .../__tests__/fixtures/sample-lua.ts | 138 +++ .../__tests__/fixtures/sample-ocaml.ts | 66 ++ .../__tests__/fixtures/sample-php.ts | 335 ++++++ .../__tests__/fixtures/sample-python.ts | 150 +++ .../__tests__/fixtures/sample-ruby.ts | 577 ++++++++++ .../__tests__/fixtures/sample-rust.ts | 308 +++++ .../__tests__/fixtures/sample-scala.ts | 94 ++ .../__tests__/fixtures/sample-solidity.ts | 102 ++ .../__tests__/fixtures/sample-swift.ts | 298 +++++ .../__tests__/fixtures/sample-systemrdl.ts | 86 ++ .../__tests__/fixtures/sample-tlaplus.ts | 49 + .../__tests__/fixtures/sample-toml.ts | 72 ++ .../__tests__/fixtures/sample-tsx.ts | 327 ++++++ .../__tests__/fixtures/sample-typescript.ts | 208 ++++ .../__tests__/fixtures/sample-vue.ts | 93 ++ .../__tests__/fixtures/sample-zig.ts | 42 + src/services/tree-sitter/__tests__/helpers.ts | 67 +- .../tree-sitter/__tests__/inspectC.test.ts | 25 + .../tree-sitter/__tests__/inspectCSS.test.ts | 27 + .../__tests__/inspectCSharp.test.ts | 24 + .../tree-sitter/__tests__/inspectCpp.test.ts | 23 + .../__tests__/inspectElisp.test.ts | 29 + .../__tests__/inspectElixir.test.ts | 26 + .../__tests__/inspectEmbeddedTemplate.test.ts | 24 + .../tree-sitter/__tests__/inspectGo.test.ts | 24 + .../tree-sitter/__tests__/inspectHtml.test.ts | 24 + .../tree-sitter/__tests__/inspectJava.test.ts | 24 + .../__tests__/inspectJavaScript.test.ts | 25 + .../tree-sitter/__tests__/inspectJson.test.ts | 21 + .../__tests__/inspectKotlin.test.ts | 21 + .../tree-sitter/__tests__/inspectLua.test.ts | 23 + .../__tests__/inspectOCaml.test.ts | 27 + .../tree-sitter/__tests__/inspectPhp.test.ts | 21 + .../__tests__/inspectPython.test.ts | 24 + .../tree-sitter/__tests__/inspectRuby.test.ts | 22 + .../tree-sitter/__tests__/inspectRust.test.ts | 33 + .../__tests__/inspectScala.test.ts | 25 + .../__tests__/inspectSolidity.test.ts | 26 + .../__tests__/inspectSwift.test.ts | 30 + .../__tests__/inspectSystemRDL.test.ts | 22 + .../__tests__/inspectTLAPlus.test.ts | 21 + .../tree-sitter/__tests__/inspectTOML.test.ts | 21 + .../tree-sitter/__tests__/inspectTsx.test.ts | 30 + .../__tests__/inspectTypeScript.test.ts | 25 + .../tree-sitter/__tests__/inspectVue.test.ts | 22 + .../tree-sitter/__tests__/inspectZig.test.ts | 20 + ...parseSourceCodeDefinitions.c-sharp.test.ts | 112 ++ .../parseSourceCodeDefinitions.c.test.ts | 114 ++ .../parseSourceCodeDefinitions.cpp.test.ts | 811 ++----------- .../parseSourceCodeDefinitions.css.test.ts | 71 ++ .../parseSourceCodeDefinitions.elisp.test.ts | 67 ++ .../parseSourceCodeDefinitions.elixir.test.ts | 90 ++ ...eCodeDefinitions.embedded_template.test.ts | 53 + .../parseSourceCodeDefinitions.go.test.ts | 425 ++----- .../parseSourceCodeDefinitions.html.test.ts | 70 ++ .../parseSourceCodeDefinitions.java.test.ts | 436 +------ ...seSourceCodeDefinitions.javascript.test.ts | 59 + .../parseSourceCodeDefinitions.json.test.ts | 201 +--- .../parseSourceCodeDefinitions.kotlin.test.ts | 23 + .../parseSourceCodeDefinitions.lua.test.ts | 51 + .../parseSourceCodeDefinitions.ocaml.test.ts | 54 + .../parseSourceCodeDefinitions.php.test.ts | 22 + .../parseSourceCodeDefinitions.python.test.ts | 578 +--------- .../parseSourceCodeDefinitions.ruby.test.ts | 106 ++ .../parseSourceCodeDefinitions.rust.test.ts | 488 +------- .../parseSourceCodeDefinitions.scala.test.ts | 92 ++ ...arseSourceCodeDefinitions.solidity.test.ts | 77 ++ .../parseSourceCodeDefinitions.swift.test.ts | 103 ++ ...rseSourceCodeDefinitions.systemrdl.test.ts | 55 + ...parseSourceCodeDefinitions.tlaplus.test.ts | 58 + .../parseSourceCodeDefinitions.toml.test.ts | 78 ++ .../parseSourceCodeDefinitions.tsx.test.ts | 1002 ++--------------- ...seSourceCodeDefinitions.typescript.test.ts | 63 ++ .../parseSourceCodeDefinitions.vue.test.ts | 58 + .../parseSourceCodeDefinitions.zig.test.ts | 38 + src/services/tree-sitter/index.ts | 77 +- src/services/tree-sitter/languageParser.ts | 70 +- src/services/tree-sitter/queries/c-sharp.ts | 74 +- src/services/tree-sitter/queries/c.ts | 86 +- src/services/tree-sitter/queries/cpp.ts | 148 ++- src/services/tree-sitter/queries/css.ts | 71 ++ src/services/tree-sitter/queries/elisp.ts | 40 + src/services/tree-sitter/queries/elixir.ts | 70 ++ .../tree-sitter/queries/embedded_template.ts | 19 + src/services/tree-sitter/queries/go.ts | 108 +- src/services/tree-sitter/queries/html.ts | 51 + src/services/tree-sitter/queries/index.ts | 14 + src/services/tree-sitter/queries/java.ts | 79 +- .../tree-sitter/queries/javascript.ts | 39 +- src/services/tree-sitter/queries/kotlin.ts | 100 +- src/services/tree-sitter/queries/lua.ts | 37 + src/services/tree-sitter/queries/ocaml.ts | 31 + src/services/tree-sitter/queries/php.ts | 165 ++- src/services/tree-sitter/queries/python.ts | 221 +--- src/services/tree-sitter/queries/ruby.ts | 232 +++- src/services/tree-sitter/queries/rust.ts | 111 +- src/services/tree-sitter/queries/scala.ts | 44 + src/services/tree-sitter/queries/solidity.ts | 44 + src/services/tree-sitter/queries/swift.ts | 97 +- src/services/tree-sitter/queries/systemrdl.ts | 33 + src/services/tree-sitter/queries/tlaplus.ts | 32 + src/services/tree-sitter/queries/toml.ts | 24 + src/services/tree-sitter/queries/tsx.ts | 209 +--- src/services/tree-sitter/queries/vue.ts | 29 + src/services/tree-sitter/queries/zig.ts | 21 + 119 files changed, 9775 insertions(+), 4280 deletions(-) create mode 100644 src/services/tree-sitter/__tests__/fixtures/sample-c-sharp.ts create mode 100644 src/services/tree-sitter/__tests__/fixtures/sample-c.ts create mode 100644 src/services/tree-sitter/__tests__/fixtures/sample-cpp.ts create mode 100644 src/services/tree-sitter/__tests__/fixtures/sample-css.ts create mode 100644 src/services/tree-sitter/__tests__/fixtures/sample-elisp.ts create mode 100644 src/services/tree-sitter/__tests__/fixtures/sample-elixir.ts create mode 100644 src/services/tree-sitter/__tests__/fixtures/sample-embedded_template.ts create mode 100644 src/services/tree-sitter/__tests__/fixtures/sample-go.ts create mode 100644 src/services/tree-sitter/__tests__/fixtures/sample-html.ts create mode 100644 src/services/tree-sitter/__tests__/fixtures/sample-java.ts create mode 100644 src/services/tree-sitter/__tests__/fixtures/sample-javascript.ts create mode 100644 src/services/tree-sitter/__tests__/fixtures/sample-json.ts create mode 100644 src/services/tree-sitter/__tests__/fixtures/sample-kotlin.ts create mode 100644 src/services/tree-sitter/__tests__/fixtures/sample-lua.ts create mode 100644 src/services/tree-sitter/__tests__/fixtures/sample-ocaml.ts create mode 100644 src/services/tree-sitter/__tests__/fixtures/sample-php.ts create mode 100644 src/services/tree-sitter/__tests__/fixtures/sample-python.ts create mode 100644 src/services/tree-sitter/__tests__/fixtures/sample-ruby.ts create mode 100644 src/services/tree-sitter/__tests__/fixtures/sample-rust.ts create mode 100644 src/services/tree-sitter/__tests__/fixtures/sample-scala.ts create mode 100644 src/services/tree-sitter/__tests__/fixtures/sample-solidity.ts create mode 100644 src/services/tree-sitter/__tests__/fixtures/sample-swift.ts create mode 100644 src/services/tree-sitter/__tests__/fixtures/sample-systemrdl.ts create mode 100644 src/services/tree-sitter/__tests__/fixtures/sample-tlaplus.ts create mode 100644 src/services/tree-sitter/__tests__/fixtures/sample-toml.ts create mode 100644 src/services/tree-sitter/__tests__/fixtures/sample-tsx.ts create mode 100644 src/services/tree-sitter/__tests__/fixtures/sample-typescript.ts create mode 100644 src/services/tree-sitter/__tests__/fixtures/sample-vue.ts create mode 100644 src/services/tree-sitter/__tests__/fixtures/sample-zig.ts create mode 100644 src/services/tree-sitter/__tests__/inspectC.test.ts create mode 100644 src/services/tree-sitter/__tests__/inspectCSS.test.ts create mode 100644 src/services/tree-sitter/__tests__/inspectCSharp.test.ts create mode 100644 src/services/tree-sitter/__tests__/inspectCpp.test.ts create mode 100644 src/services/tree-sitter/__tests__/inspectElisp.test.ts create mode 100644 src/services/tree-sitter/__tests__/inspectElixir.test.ts create mode 100644 src/services/tree-sitter/__tests__/inspectEmbeddedTemplate.test.ts create mode 100644 src/services/tree-sitter/__tests__/inspectGo.test.ts create mode 100644 src/services/tree-sitter/__tests__/inspectHtml.test.ts create mode 100644 src/services/tree-sitter/__tests__/inspectJava.test.ts create mode 100644 src/services/tree-sitter/__tests__/inspectJavaScript.test.ts create mode 100644 src/services/tree-sitter/__tests__/inspectJson.test.ts create mode 100644 src/services/tree-sitter/__tests__/inspectKotlin.test.ts create mode 100644 src/services/tree-sitter/__tests__/inspectLua.test.ts create mode 100644 src/services/tree-sitter/__tests__/inspectOCaml.test.ts create mode 100644 src/services/tree-sitter/__tests__/inspectPhp.test.ts create mode 100644 src/services/tree-sitter/__tests__/inspectPython.test.ts create mode 100644 src/services/tree-sitter/__tests__/inspectRuby.test.ts create mode 100644 src/services/tree-sitter/__tests__/inspectRust.test.ts create mode 100644 src/services/tree-sitter/__tests__/inspectScala.test.ts create mode 100644 src/services/tree-sitter/__tests__/inspectSolidity.test.ts create mode 100644 src/services/tree-sitter/__tests__/inspectSwift.test.ts create mode 100644 src/services/tree-sitter/__tests__/inspectSystemRDL.test.ts create mode 100644 src/services/tree-sitter/__tests__/inspectTLAPlus.test.ts create mode 100644 src/services/tree-sitter/__tests__/inspectTOML.test.ts create mode 100644 src/services/tree-sitter/__tests__/inspectTsx.test.ts create mode 100644 src/services/tree-sitter/__tests__/inspectTypeScript.test.ts create mode 100644 src/services/tree-sitter/__tests__/inspectVue.test.ts create mode 100644 src/services/tree-sitter/__tests__/inspectZig.test.ts create mode 100644 src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.c-sharp.test.ts create mode 100644 src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.c.test.ts create mode 100644 src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.css.test.ts create mode 100644 src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.elisp.test.ts create mode 100644 src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.elixir.test.ts create mode 100644 src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.embedded_template.test.ts create mode 100644 src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.html.test.ts create mode 100644 src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.javascript.test.ts create mode 100644 src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.kotlin.test.ts create mode 100644 src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.lua.test.ts create mode 100644 src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.ocaml.test.ts create mode 100644 src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.php.test.ts create mode 100644 src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.ruby.test.ts create mode 100644 src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.scala.test.ts create mode 100644 src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.solidity.test.ts create mode 100644 src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.swift.test.ts create mode 100644 src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.systemrdl.test.ts create mode 100644 src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.tlaplus.test.ts create mode 100644 src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.toml.test.ts create mode 100644 src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.typescript.test.ts create mode 100644 src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.vue.test.ts create mode 100644 src/services/tree-sitter/__tests__/parseSourceCodeDefinitions.zig.test.ts create mode 100644 src/services/tree-sitter/queries/css.ts create mode 100644 src/services/tree-sitter/queries/elisp.ts create mode 100644 src/services/tree-sitter/queries/elixir.ts create mode 100644 src/services/tree-sitter/queries/embedded_template.ts create mode 100644 src/services/tree-sitter/queries/html.ts create mode 100644 src/services/tree-sitter/queries/lua.ts create mode 100644 src/services/tree-sitter/queries/ocaml.ts create mode 100644 src/services/tree-sitter/queries/scala.ts create mode 100644 src/services/tree-sitter/queries/solidity.ts create mode 100644 src/services/tree-sitter/queries/systemrdl.ts create mode 100644 src/services/tree-sitter/queries/tlaplus.ts create mode 100644 src/services/tree-sitter/queries/toml.ts create mode 100644 src/services/tree-sitter/queries/vue.ts create mode 100644 src/services/tree-sitter/queries/zig.ts diff --git a/esbuild.js b/esbuild.js index c6a555f5a5..68cf880638 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", - ] + // 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")) - languages.forEach((lang) => { - const filename = `tree-sitter-${lang}.wasm` - fs.copyFileSync(path.join(languageWasmDir, filename), path.join(distDir, filename)) - }) + 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 0000000000..f1174f6e4c --- /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 0000000000..41ea927de9 --- /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 0000000000..7cba1a7df9 --- /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 0000000000..d74163d9b9 --- /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 0000000000..e0f21dd4ba --- /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 0000000000..5ed6dc9b00 --- /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 0000000000..d78ea5c273 --- /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 0000000000..3b761c141e --- /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 0000000000..44392ff451 --- /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 0000000000..80ecaf2da2 --- /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 0000000000..db5afb98be --- /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 0000000000..babb4aa7a4 --- /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 0000000000..2f8b59c11b --- /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 0000000000..4d22199a0f --- /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 0000000000..7b52b74cef --- /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 0000000000..99bfabba1c --- /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 0000000000..b3416999a5 --- /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 0000000000..1c42e978ee --- /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 0000000000..9b37462b36 --- /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 0000000000..df93dfd930 --- /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 0000000000..ac4a42f7ce --- /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 0000000000..5dea06402c --- /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 0000000000..a490396e9c --- /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 0000000000..a976fa83ad --- /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 0000000000..9b4ba1036b --- /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 0000000000..2a9149d7a6 --- /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 0000000000..9e092ead8f --- /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 0000000000..1a8a33c80c --- /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 0000000000..661a884bf5 --- /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 522e6c1cc3..3326e1c89b 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 0000000000..8e397ce993 --- /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 0000000000..1f3d1a6a96 --- /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 0000000000..d8d0183941 --- /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 0000000000..b6e28cf19a --- /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 0000000000..242019177b --- /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 0000000000..a756b1cd9f --- /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 0000000000..4d2157cca6 --- /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 0000000000..185867d1eb --- /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 0000000000..bc7a2c34c2 --- /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 0000000000..c5d7387473 --- /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 0000000000..e8c3506ae6 --- /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 0000000000..df9a3e557b --- /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 0000000000..0868bbd5d6 --- /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 0000000000..0a18cb87c1 --- /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 0000000000..a120b2bcd7 --- /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 0000000000..99c0132fac --- /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 0000000000..f95c080114 --- /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 0000000000..2d7c1896d5 --- /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 0000000000..a8323fb284 --- /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 0000000000..94492c297a --- /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 0000000000..8c515963f7 --- /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 0000000000..f7d2266a70 --- /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 0000000000..95094b4518 --- /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 0000000000..3e1e733294 --- /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 0000000000..acf5976578 --- /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 0000000000..f7f58a8533 --- /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 0000000000..08695f6bfe --- /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 0000000000..62037bd4b8 --- /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 0000000000..52facd4c4c --- /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 0000000000..020625d5c3 --- /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 43c03a1ea5..15811c55ea 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; +TODO: The following C++ structures can be parsed by tree-sitter but lack query support: -template -T add(T a, T b) { - return a + b; -} +1. Virtual Methods: + (field_declaration (virtual) type: (primitive_type) declarator: (function_declarator)) + Example: virtual void method() = 0; + +2. Default Methods: + (default_method_clause) + Example: virtual ~base_class_definition() = default; + +3. Field Initializer Lists: + (field_initializer_list (field_initializer)) + Example: constructor() : field1(value1), field2(value2) {} + +4. Base Class Clauses: + (base_class_clause (access_specifier) (type_identifier)) + Example: class derived : public base {} + +5. Type Aliases: + (alias_declaration name: (type_identifier) type: (type_descriptor)) + Example: using size_type = std::size_t; */ -// 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; - } -}; +import { describe, it, expect, beforeAll } from "@jest/globals" +import { testParseSourceCodeDefinitions } from "./helpers" +import { cppQuery } from "../queries" +import sampleCppContent from "./fixtures/sample-cpp" -// 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; - } -}; +describe("parseSourceCodeDefinitions (C++)", () => { + const testOptions = { + language: "cpp", + wasmFile: "tree-sitter-cpp.wasm", + queryString: cppQuery, + extKey: "cpp", + } -// Function with trailing return type -auto multiply(int a, int b) -> int { - return a * b; -} + let parseResult: string -// 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; - } -}; -` - -// C++ test options -const cppOptions = { - language: "cpp", - wasmFile: "tree-sitter-cpp.wasm", - queryString: cppQuery, - extKey: "cpp", - content: sampleCppContent, -} - -// 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++", () => { - 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 macro definitions", () => { + expect(parseResult).toMatch(/\d+--\d+ \| #define MULTI_LINE_MACRO\(x, y\)/) }) - 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 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 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 constructor declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*constructor_test\(/) }) - 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 destructor declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*~destructor_test\(\)/) }) - 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 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 virtual functions - checking for virtual keyword - expect(resultLines.some((line) => line.includes("virtual"))).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++ 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 C++ inline functions and variables", async () => { - // 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 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 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 C++ advanced class features", async () => { - 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 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 0000000000..dc4857c57f --- /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 0000000000..196d838394 --- /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 0000000000..d16dcb062a --- /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 0000000000..523907923c --- /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 137809626d..57fc804135 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" +/* +TODO: The following structures can be parsed by tree-sitter but lack query support: -import { goQuery } from "../queries" +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" +import goQuery from "../queries/go" -// 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 +describe("Go Source Code Definition Tests", () => { + let parseResult: string -import ( - "fmt" - "math" - "strings" -) + beforeAll(async () => { + const testOptions = { + language: "go", + wasmFile: "tree-sitter-go.wasm", + queryString: goQuery, + extKey: "go", + } -// 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() + 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") || [] + it("should parse goroutine function declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*func TestGoroutineDefinition\(\)/) + }) - // 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) + it("should parse defer function declarations", () => { + expect(parseResult).toMatch(/\d+--\d+ \|\s*func TestDeferDefinition\(\)/) + }) - // 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) - - // 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.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 0000000000..1ac6d55024 --- /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*