import { describe, it, expect } from 'vitest'; import { parseTypeScript } from './parser'; describe('parseTypeScript', () => { describe('function declarations', () => { it('extracts a regular function declaration', () => { const content = `function greet(name) { return 'hello ' + name; }`; const result = parseTypeScript(content); expect(result.functions).toHaveLength(1); expect(result.functions[0].name).toBe('greet'); expect(result.functions[0].params).toEqual(['name']); expect(result.functions[0].isExported).toBe(false); expect(result.functions[0].startLine).toBe(1); expect(result.functions[0].endLine).toBe(3); }); it('extracts an async function declaration', () => { const content = `async function fetchData(url, options) { const res = await fetch(url, options); return res.json(); }`; const result = parseTypeScript(content); expect(result.functions).toHaveLength(1); expect(result.functions[0].name).toBe('fetchData'); expect(result.functions[0].params).toEqual(['url', 'options']); expect(result.functions[0].isExported).toBe(false); }); it('extracts an exported function declaration', () => { const content = `export function calculate(a, b) { return a + b; }`; const result = parseTypeScript(content); expect(result.functions).toHaveLength(1); expect(result.functions[0].name).toBe('calculate'); expect(result.functions[0].isExported).toBe(true); expect(result.exports).toContain('calculate'); }); it('extracts an export default function', () => { const content = `export default function main() { console.log('hello'); }`; const result = parseTypeScript(content); expect(result.functions).toHaveLength(1); expect(result.functions[0].name).toBe('main'); expect(result.functions[0].isExported).toBe(true); }); it('extracts a generator function', () => { const content = `function* generate(items) { for (const item of items) { yield item; } }`; const result = parseTypeScript(content); expect(result.functions).toHaveLength(1); expect(result.functions[0].name).toBe('generate'); expect(result.functions[0].params).toEqual(['items']); }); }); describe('arrow functions', () => { it('extracts a const arrow function', () => { const content = `const add = (a, b) => { return a + b; }`; const result = parseTypeScript(content); expect(result.functions).toHaveLength(1); expect(result.functions[0].name).toBe('add'); expect(result.functions[0].params).toEqual(['a', 'b']); expect(result.functions[0].isExported).toBe(false); }); it('extracts an exported arrow function', () => { const content = `export const multiply = (x, y) => { return x * y; }`; const result = parseTypeScript(content); expect(result.functions).toHaveLength(1); expect(result.functions[0].name).toBe('multiply'); expect(result.functions[0].isExported).toBe(true); expect(result.exports).toContain('multiply'); }); it('extracts an async arrow function', () => { const content = `const loadData = async (id) => { const res = await fetch('/api/' + id); return res.json(); }`; const result = parseTypeScript(content); expect(result.functions).toHaveLength(1); expect(result.functions[0].name).toBe('loadData'); expect(result.functions[0].params).toEqual(['id']); }); it('extracts an arrow function with no params', () => { const content = `const noop = () => { // do nothing }`; const result = parseTypeScript(content); expect(result.functions).toHaveLength(1); expect(result.functions[0].name).toBe('noop'); expect(result.functions[0].params).toEqual([]); }); it('extracts arrow function with TypeScript type annotations', () => { const content = `export const process = (input: string, count: number): boolean => { return input.length > count; }`; const result = parseTypeScript(content); expect(result.functions).toHaveLength(1); expect(result.functions[0].name).toBe('process'); expect(result.functions[0].params).toEqual(['input', 'count']); }); }); describe('class declarations', () => { it('extracts a class with methods', () => { const content = `class UserService { constructor(db) { this.db = db; } getUser(id) { return this.db.find(id); } async createUser(data) { return this.db.insert(data); } }`; const result = parseTypeScript(content); expect(result.classes).toHaveLength(1); expect(result.classes[0].name).toBe('UserService'); expect(result.classes[0].isExported).toBe(false); expect(result.classes[0].methods).toContain('constructor'); expect(result.classes[0].methods).toContain('getUser'); expect(result.classes[0].methods).toContain('createUser'); expect(result.classes[0].startLine).toBe(1); }); it('extracts an exported class', () => { const content = `export class ApiClient { fetch(url) { return fetch(url); } }`; const result = parseTypeScript(content); expect(result.classes).toHaveLength(1); expect(result.classes[0].name).toBe('ApiClient'); expect(result.classes[0].isExported).toBe(true); expect(result.classes[0].methods).toContain('fetch'); expect(result.exports).toContain('ApiClient'); }); it('extracts an export default class', () => { const content = `export default class App { run() { console.log('running'); } }`; const result = parseTypeScript(content); expect(result.classes).toHaveLength(1); expect(result.classes[0].name).toBe('App'); expect(result.classes[0].isExported).toBe(true); }); it('extracts an abstract class', () => { const content = `abstract class BaseRepository { abstract find(id); save(entity) { return this.persist(entity); } }`; const result = parseTypeScript(content); expect(result.classes).toHaveLength(1); expect(result.classes[0].name).toBe('BaseRepository'); expect(result.classes[0].methods).toContain('find'); expect(result.classes[0].methods).toContain('save'); }); it('extracts getter and setter methods', () => { const content = `class Config { get value() { return this._value; } set value(v) { this._value = v; } }`; const result = parseTypeScript(content); expect(result.classes).toHaveLength(1); expect(result.classes[0].methods).toContain('value'); }); }); describe('import statements', () => { it('extracts named imports', () => { const content = `import { readFile, writeFile } from 'fs';`; const result = parseTypeScript(content); expect(result.imports).toHaveLength(1); expect(result.imports[0].source).toBe('fs'); expect(result.imports[0].names).toEqual(['readFile', 'writeFile']); }); it('extracts default imports', () => { const content = `import express from 'express';`; const result = parseTypeScript(content); expect(result.imports).toHaveLength(1); expect(result.imports[0].source).toBe('express'); expect(result.imports[0].names).toEqual(['express']); }); it('extracts namespace imports', () => { const content = `import * as path from 'path';`; const result = parseTypeScript(content); expect(result.imports).toHaveLength(1); expect(result.imports[0].source).toBe('path'); expect(result.imports[0].names).toEqual(['path']); }); it('extracts side-effect imports', () => { const content = `import './styles.css';`; const result = parseTypeScript(content); expect(result.imports).toHaveLength(1); expect(result.imports[0].source).toBe('./styles.css'); expect(result.imports[0].names).toEqual([]); }); it('extracts require calls', () => { const content = `const fs = require('fs');`; const result = parseTypeScript(content); expect(result.imports).toHaveLength(1); expect(result.imports[0].source).toBe('fs'); expect(result.imports[0].names).toEqual(['fs']); }); it('extracts destructured require calls', () => { const content = `const { join, resolve } = require('path');`; const result = parseTypeScript(content); expect(result.imports).toHaveLength(1); expect(result.imports[0].source).toBe('path'); expect(result.imports[0].names).toEqual(['join', 'resolve']); }); it('extracts import with alias', () => { const content = `import { readFile as read, writeFile as write } from 'fs';`; const result = parseTypeScript(content); expect(result.imports).toHaveLength(1); expect(result.imports[0].source).toBe('fs'); expect(result.imports[0].names).toEqual(['read', 'write']); }); it('extracts mixed default and named imports', () => { const content = `import React, { useState, useEffect } from 'react';`; const result = parseTypeScript(content); expect(result.imports).toHaveLength(1); expect(result.imports[0].source).toBe('react'); expect(result.imports[0].names).toContain('React'); expect(result.imports[0].names).toContain('useState'); expect(result.imports[0].names).toContain('useEffect'); }); }); describe('export statements', () => { it('extracts named exports', () => { const content = `const a = 1; const b = 2; export { a, b };`; const result = parseTypeScript(content); expect(result.exports).toContain('a'); expect(result.exports).toContain('b'); }); it('extracts export default identifier', () => { const content = `const config = {}; export default config;`; const result = parseTypeScript(content); expect(result.exports).toContain('config'); }); it('extracts export const/let/var', () => { const content = `export const API_URL = 'http://localhost'; export let counter = 0; export var legacy = true;`; const result = parseTypeScript(content); expect(result.exports).toContain('API_URL'); expect(result.exports).toContain('counter'); expect(result.exports).toContain('legacy'); }); it('extracts re-exports with alias', () => { const content = `export { default as MyComponent } from './component';`; const result = parseTypeScript(content); expect(result.exports).toContain('MyComponent'); }); }); describe('mixed content', () => { it('handles a file with multiple declarations', () => { const content = `import { readFileSync } from 'fs'; import path from 'path'; export interface Config { name: string; } export function loadConfig(filePath) { const content = readFileSync(filePath, 'utf-8'); return JSON.parse(content); } const DEFAULT_PATH = './config.json'; export const getDefaultConfig = () => { return loadConfig(DEFAULT_PATH); } export class ConfigManager { constructor(config) { this.config = config; } get(key) { return this.config[key]; } set(key, value) { this.config[key] = value; } } export default ConfigManager;`; const result = parseTypeScript(content); // Imports expect(result.imports).toHaveLength(2); expect(result.imports[0].source).toBe('fs'); expect(result.imports[1].source).toBe('path'); // Functions expect(result.functions.length).toBeGreaterThanOrEqual(2); const loadConfigFn = result.functions.find((f) => f.name === 'loadConfig'); expect(loadConfigFn).toBeDefined(); expect(loadConfigFn.isExported).toBe(true); const getDefaultFn = result.functions.find((f) => f.name === 'getDefaultConfig'); expect(getDefaultFn).toBeDefined(); expect(getDefaultFn.isExported).toBe(true); // Classes expect(result.classes).toHaveLength(1); expect(result.classes[0].name).toBe('ConfigManager'); expect(result.classes[0].isExported).toBe(true); expect(result.classes[0].methods).toContain('constructor'); expect(result.classes[0].methods).toContain('get'); expect(result.classes[0].methods).toContain('set'); // Exports expect(result.exports).toContain('loadConfig'); expect(result.exports).toContain('getDefaultConfig'); expect(result.exports).toContain('ConfigManager'); }); it('handles empty content', () => { const result = parseTypeScript(''); expect(result.functions).toEqual([]); expect(result.classes).toEqual([]); expect(result.imports).toEqual([]); expect(result.exports).toEqual([]); }); it('handles content with only comments', () => { const content = `// This is a comment /* Multi-line comment */ // Another comment`; const result = parseTypeScript(content); expect(result.functions).toEqual([]); expect(result.classes).toEqual([]); expect(result.imports).toEqual([]); expect(result.exports).toEqual([]); }); }); }); import { parsePython } from './parser'; describe('parsePython', () => { describe('function definitions', () => { it('extracts a regular function definition', () => { const content = `def greet(name): return 'hello ' + name `; const result = parsePython(content); expect(result.functions).toHaveLength(1); expect(result.functions[0].name).toBe('greet'); expect(result.functions[0].params).toEqual(['name']); expect(result.functions[0].isExported).toBe(true); expect(result.functions[0].startLine).toBe(1); expect(result.functions[0].endLine).toBe(2); }); it('extracts an async function definition', () => { const content = `async def fetch_data(url, timeout=30): response = await aiohttp.get(url, timeout=timeout) return response.json() `; const result = parsePython(content); expect(result.functions).toHaveLength(1); expect(result.functions[0].name).toBe('fetch_data'); expect(result.functions[0].params).toEqual(['url', 'timeout']); expect(result.functions[0].isExported).toBe(true); }); it('extracts function with type annotations', () => { const content = `def process(input: str, count: int = 0) -> bool: return len(input) > count `; const result = parsePython(content); expect(result.functions).toHaveLength(1); expect(result.functions[0].name).toBe('process'); expect(result.functions[0].params).toEqual(['input', 'count']); }); it('marks private functions (underscore prefix) as not exported', () => { const content = `def _helper(x): return x * 2 def public_func(y): return _helper(y) `; const result = parsePython(content); expect(result.functions).toHaveLength(2); const helper = result.functions.find((f) => f.name === '_helper'); expect(helper).toBeDefined(); expect(helper.isExported).toBe(false); const pub = result.functions.find((f) => f.name === 'public_func'); expect(pub).toBeDefined(); expect(pub.isExported).toBe(true); }); it('extracts function with *args and **kwargs', () => { const content = `def variadic(a, *args, **kwargs): pass `; const result = parsePython(content); expect(result.functions).toHaveLength(1); expect(result.functions[0].params).toEqual(['a', 'args', 'kwargs']); }); it('handles multiple functions', () => { const content = `def first(): pass def second(x): return x `; const result = parsePython(content); expect(result.functions).toHaveLength(2); expect(result.functions[0].name).toBe('first'); expect(result.functions[1].name).toBe('second'); }); }); describe('class definitions', () => { it('extracts a class with methods', () => { const content = `class UserService: def __init__(self, db): self.db = db def get_user(self, user_id): return self.db.find(user_id) async def create_user(self, data): return await self.db.insert(data) `; const result = parsePython(content); expect(result.classes).toHaveLength(1); expect(result.classes[0].name).toBe('UserService'); expect(result.classes[0].isExported).toBe(true); expect(result.classes[0].methods).toContain('__init__'); expect(result.classes[0].methods).toContain('get_user'); expect(result.classes[0].methods).toContain('create_user'); expect(result.classes[0].startLine).toBe(1); }); it('extracts a class with inheritance', () => { const content = `class ApiClient(BaseClient): def fetch(self, url): return self.session.get(url) `; const result = parsePython(content); expect(result.classes).toHaveLength(1); expect(result.classes[0].name).toBe('ApiClient'); expect(result.classes[0].isExported).toBe(true); expect(result.classes[0].methods).toContain('fetch'); }); it('marks private classes as not exported', () => { const content = `class _InternalHelper: def do_work(self): pass class PublicApi: def run(self): pass `; const result = parsePython(content); expect(result.classes).toHaveLength(2); const internal = result.classes.find((c) => c.name === '_InternalHelper'); expect(internal).toBeDefined(); expect(internal.isExported).toBe(false); const pub = result.classes.find((c) => c.name === 'PublicApi'); expect(pub).toBeDefined(); expect(pub.isExported).toBe(true); }); it('extracts class with multiple base classes', () => { const content = `class MyView(View, Mixin): def get(self, request): pass `; const result = parsePython(content); expect(result.classes).toHaveLength(1); expect(result.classes[0].name).toBe('MyView'); expect(result.classes[0].methods).toContain('get'); }); }); describe('import statements', () => { it('extracts simple import', () => { const content = `import os`; const result = parsePython(content); expect(result.imports).toHaveLength(1); expect(result.imports[0].source).toBe('os'); expect(result.imports[0].names).toEqual(['os']); }); it('extracts import with alias', () => { const content = `import numpy as np`; const result = parsePython(content); expect(result.imports).toHaveLength(1); expect(result.imports[0].source).toBe('numpy'); expect(result.imports[0].names).toEqual(['np']); }); it('extracts from...import', () => { const content = `from os.path import join, dirname`; const result = parsePython(content); expect(result.imports).toHaveLength(1); expect(result.imports[0].source).toBe('os.path'); expect(result.imports[0].names).toEqual(['join', 'dirname']); }); it('extracts from...import with alias', () => { const content = `from collections import OrderedDict as OD`; const result = parsePython(content); expect(result.imports).toHaveLength(1); expect(result.imports[0].source).toBe('collections'); expect(result.imports[0].names).toEqual(['OD']); }); it('extracts from...import wildcard', () => { const content = `from module import *`; const result = parsePython(content); expect(result.imports).toHaveLength(1); expect(result.imports[0].source).toBe('module'); expect(result.imports[0].names).toEqual(['*']); }); it('extracts multi-line from...import with parentheses', () => { const content = `from flask import ( Flask, request, jsonify )`; const result = parsePython(content); expect(result.imports).toHaveLength(1); expect(result.imports[0].source).toBe('flask'); expect(result.imports[0].names).toEqual(['Flask', 'request', 'jsonify']); }); it('extracts multiple comma-separated imports', () => { const content = `import os, sys`; const result = parsePython(content); expect(result.imports).toHaveLength(2); expect(result.imports[0].source).toBe('os'); expect(result.imports[0].names).toEqual(['os']); expect(result.imports[1].source).toBe('sys'); expect(result.imports[1].names).toEqual(['sys']); }); }); describe('indentation-based end detection', () => { it('detects function end based on indentation', () => { const content = `def first(): x = 1 return x def second(): return 2 `; const result = parsePython(content); expect(result.functions).toHaveLength(2); expect(result.functions[0].name).toBe('first'); expect(result.functions[0].startLine).toBe(1); expect(result.functions[0].endLine).toBe(3); expect(result.functions[1].name).toBe('second'); expect(result.functions[1].startLine).toBe(5); expect(result.functions[1].endLine).toBe(6); }); it('detects class end based on indentation', () => { const content = `class MyClass: def method_a(self): return 1 def method_b(self): return 2 def standalone(): pass `; const result = parsePython(content); expect(result.classes).toHaveLength(1); expect(result.classes[0].startLine).toBe(1); expect(result.classes[0].endLine).toBe(6); expect(result.functions).toHaveLength(1); expect(result.functions[0].name).toBe('standalone'); }); it('handles function at end of file without trailing newline', () => { const content = `def last_func(): return 42`; const result = parsePython(content); expect(result.functions).toHaveLength(1); expect(result.functions[0].endLine).toBe(2); }); }); describe('exports and __all__', () => { it('collects public names as exports by default', () => { const content = `def public_one(): pass def _private(): pass class PublicClass: pass class _PrivateClass: pass `; const result = parsePython(content); expect(result.exports).toContain('public_one'); expect(result.exports).toContain('PublicClass'); expect(result.exports).not.toContain('_private'); expect(result.exports).not.toContain('_PrivateClass'); }); it('uses __all__ when defined', () => { const content = `__all__ = ['exported_func', 'ExportedClass'] def exported_func(): pass def other_func(): pass class ExportedClass: pass `; const result = parsePython(content); expect(result.exports).toEqual(['exported_func', 'ExportedClass']); }); }); describe('mixed content', () => { it('handles a typical Python module', () => { const content = `import os from pathlib import Path class Config: def __init__(self, path: str): self.path = path def load(self): return Path(self.path).read_text() def create_config(path: str) -> Config: return Config(path) def _validate(data): return bool(data) `; const result = parsePython(content); // Imports expect(result.imports).toHaveLength(2); expect(result.imports[0].source).toBe('os'); expect(result.imports[1].source).toBe('pathlib'); expect(result.imports[1].names).toEqual(['Path']); // Classes expect(result.classes).toHaveLength(1); expect(result.classes[0].name).toBe('Config'); expect(result.classes[0].methods).toContain('__init__'); expect(result.classes[0].methods).toContain('load'); // Functions (only top-level, not class methods) const topFuncs = result.functions; expect(topFuncs).toHaveLength(2); expect(topFuncs[0].name).toBe('create_config'); expect(topFuncs[1].name).toBe('_validate'); // Exports expect(result.exports).toContain('Config'); expect(result.exports).toContain('create_config'); expect(result.exports).not.toContain('_validate'); }); it('handles empty content', () => { const result = parsePython(''); expect(result.functions).toEqual([]); expect(result.classes).toEqual([]); expect(result.imports).toEqual([]); expect(result.exports).toEqual([]); }); it('handles content with only comments', () => { const content = `# This is a comment # Another comment """ Module docstring """`; const result = parsePython(content); expect(result.functions).toEqual([]); expect(result.classes).toEqual([]); expect(result.imports).toEqual([]); expect(result.exports).toEqual([]); }); }); }); import { parseGo, parseRust, parseJava, parseGeneric } from './parser'; describe('parseGo', () => { describe('function declarations', () => { it('extracts a regular function', () => { const content = `func main() { fmt.Println("hello") }`; const result = parseGo(content); expect(result.functions).toHaveLength(1); expect(result.functions[0].name).toBe('main'); expect(result.functions[0].params).toEqual([]); expect(result.functions[0].startLine).toBe(1); expect(result.functions[0].endLine).toBe(3); }); it('extracts a function with parameters', () => { const content = `func Add(a int, b int) int { return a + b }`; const result = parseGo(content); expect(result.functions).toHaveLength(1); expect(result.functions[0].name).toBe('Add'); expect(result.functions[0].params).toEqual(['a', 'b']); expect(result.functions[0].isExported).toBe(true); }); it('extracts a method with receiver', () => { const content = `func (s *Server) Start(port int) error { return s.listen(port) }`; const result = parseGo(content); expect(result.functions).toHaveLength(1); expect(result.functions[0].name).toBe('Start'); expect(result.functions[0].params).toEqual(['port']); expect(result.functions[0].isExported).toBe(true); }); it('marks lowercase functions as unexported', () => { const content = `func helper(x int) int { return x * 2 }`; const result = parseGo(content); expect(result.functions[0].isExported).toBe(false); expect(result.exports).not.toContain('helper'); }); it('marks uppercase functions as exported', () => { const content = `func HandleRequest(w http.ResponseWriter, r *http.Request) { w.Write([]byte("ok")) }`; const result = parseGo(content); expect(result.functions[0].isExported).toBe(true); expect(result.exports).toContain('HandleRequest'); }); }); describe('type declarations', () => { it('extracts a struct type', () => { const content = `type Server struct { host string port int }`; const result = parseGo(content); expect(result.classes).toHaveLength(1); expect(result.classes[0].name).toBe('Server'); expect(result.classes[0].isExported).toBe(true); expect(result.classes[0].startLine).toBe(1); expect(result.classes[0].endLine).toBe(4); }); it('extracts an interface type with methods', () => { const content = `type Reader interface { Read(p []byte) (int, error) Close() error }`; const result = parseGo(content); expect(result.classes).toHaveLength(1); expect(result.classes[0].name).toBe('Reader'); expect(result.classes[0].isExported).toBe(true); expect(result.classes[0].methods).toContain('Read'); expect(result.classes[0].methods).toContain('Close'); }); it('marks lowercase types as unexported', () => { const content = `type config struct { name string }`; const result = parseGo(content); expect(result.classes[0].isExported).toBe(false); expect(result.exports).not.toContain('config'); }); }); describe('import statements', () => { it('extracts a single import', () => { const content = `import "fmt"`; const result = parseGo(content); expect(result.imports).toHaveLength(1); expect(result.imports[0].source).toBe('fmt'); expect(result.imports[0].names).toEqual(['fmt']); }); it('extracts a block import', () => { const content = `import ( "fmt" "net/http" "os" )`; const result = parseGo(content); expect(result.imports).toHaveLength(3); expect(result.imports[0].source).toBe('fmt'); expect(result.imports[1].source).toBe('net/http'); expect(result.imports[1].names).toEqual(['http']); expect(result.imports[2].source).toBe('os'); }); it('extracts aliased imports', () => { const content = `import ( mux "github.com/gorilla/mux" )`; const result = parseGo(content); expect(result.imports).toHaveLength(1); expect(result.imports[0].source).toBe('github.com/gorilla/mux'); expect(result.imports[0].names).toEqual(['mux']); }); }); describe('empty content', () => { it('handles empty content', () => { const result = parseGo(''); expect(result.functions).toEqual([]); expect(result.classes).toEqual([]); expect(result.imports).toEqual([]); expect(result.exports).toEqual([]); }); }); }); describe('parseRust', () => { describe('function declarations', () => { it('extracts a public function', () => { const content = `pub fn add(a: i32, b: i32) -> i32 { a + b }`; const result = parseRust(content); expect(result.functions).toHaveLength(1); expect(result.functions[0].name).toBe('add'); expect(result.functions[0].params).toEqual(['a', 'b']); expect(result.functions[0].isExported).toBe(true); expect(result.functions[0].startLine).toBe(1); expect(result.functions[0].endLine).toBe(3); }); it('extracts a private function', () => { const content = `fn helper(x: u32) -> u32 { x * 2 }`; const result = parseRust(content); expect(result.functions).toHaveLength(1); expect(result.functions[0].name).toBe('helper'); expect(result.functions[0].isExported).toBe(false); }); it('extracts an async function', () => { const content = `pub async fn fetch_data(url: &str) -> Result { reqwest::get(url).await?.text().await }`; const result = parseRust(content); expect(result.functions).toHaveLength(1); expect(result.functions[0].name).toBe('fetch_data'); expect(result.functions[0].params).toEqual(['url']); expect(result.functions[0].isExported).toBe(true); }); }); describe('struct and enum declarations', () => { it('extracts a public struct', () => { const content = `pub struct Config { pub name: String, pub port: u16, }`; const result = parseRust(content); expect(result.classes).toHaveLength(1); expect(result.classes[0].name).toBe('Config'); expect(result.classes[0].isExported).toBe(true); expect(result.exports).toContain('Config'); }); it('extracts an enum', () => { const content = `pub enum Status { Active, Inactive, Pending, }`; const result = parseRust(content); expect(result.classes).toHaveLength(1); expect(result.classes[0].name).toBe('Status'); expect(result.classes[0].isExported).toBe(true); }); it('extracts a private struct', () => { const content = `struct Internal { data: Vec, }`; const result = parseRust(content); expect(result.classes).toHaveLength(1); expect(result.classes[0].name).toBe('Internal'); expect(result.classes[0].isExported).toBe(false); }); }); describe('impl blocks', () => { it('extracts methods from impl block', () => { const content = `pub struct Server { port: u16, } impl Server { pub fn new(port: u16) -> Self { Server { port } } pub fn start(&self) { println!("Starting on port {}", self.port); } fn internal_helper(&self) { // private } }`; const result = parseRust(content); expect(result.classes).toHaveLength(1); expect(result.classes[0].name).toBe('Server'); expect(result.classes[0].methods).toContain('new'); expect(result.classes[0].methods).toContain('start'); expect(result.classes[0].methods).toContain('internal_helper'); }); }); describe('use statements', () => { it('extracts a simple use statement', () => { const content = `use std::collections::HashMap;`; const result = parseRust(content); expect(result.imports).toHaveLength(1); expect(result.imports[0].source).toBe('std::collections::HashMap'); expect(result.imports[0].names).toEqual(['HashMap']); }); it('extracts grouped use statements', () => { const content = `use std::collections::{HashMap, HashSet};`; const result = parseRust(content); expect(result.imports).toHaveLength(1); expect(result.imports[0].source).toBe('std::collections'); expect(result.imports[0].names).toEqual(['HashMap', 'HashSet']); }); it('extracts crate use statements', () => { const content = `use crate::config::Settings;`; const result = parseRust(content); expect(result.imports).toHaveLength(1); expect(result.imports[0].source).toBe('crate::config::Settings'); expect(result.imports[0].names).toEqual(['Settings']); }); }); describe('empty content', () => { it('handles empty content', () => { const result = parseRust(''); expect(result.functions).toEqual([]); expect(result.classes).toEqual([]); expect(result.imports).toEqual([]); expect(result.exports).toEqual([]); }); }); }); describe('parseJava', () => { describe('class declarations', () => { it('extracts a public class with methods', () => { const content = `public class UserService { public User getUser(int id) { return db.find(id); } private void validate(User user) { // validation logic } }`; const result = parseJava(content); expect(result.classes).toHaveLength(1); expect(result.classes[0].name).toBe('UserService'); expect(result.classes[0].isExported).toBe(true); expect(result.classes[0].methods).toContain('getUser'); expect(result.classes[0].methods).toContain('validate'); }); it('extracts an interface', () => { const content = `public interface Repository { Object find(int id); void save(Object entity); }`; const result = parseJava(content); expect(result.classes).toHaveLength(1); expect(result.classes[0].name).toBe('Repository'); expect(result.classes[0].isExported).toBe(true); }); it('extracts a private class', () => { const content = `class InternalHelper { void doWork() { // work } }`; const result = parseJava(content); expect(result.classes).toHaveLength(1); expect(result.classes[0].name).toBe('InternalHelper'); expect(result.classes[0].isExported).toBe(false); }); }); describe('method extraction', () => { it('extracts public methods as exported functions', () => { const content = `public class Api { public String getData(String key) { return map.get(key); } public void setData(String key, String value) { map.put(key, value); } }`; const result = parseJava(content); const getDataFn = result.functions.find((f) => f.name === 'getData'); expect(getDataFn).toBeDefined(); expect(getDataFn.isExported).toBe(true); expect(getDataFn.params).toEqual(['key']); const setDataFn = result.functions.find((f) => f.name === 'setData'); expect(setDataFn).toBeDefined(); expect(setDataFn.params).toEqual(['key', 'value']); }); }); describe('import statements', () => { it('extracts import statements', () => { const content = `import java.util.List; import java.util.Map; import com.example.service.UserService;`; const result = parseJava(content); expect(result.imports).toHaveLength(3); expect(result.imports[0].source).toBe('java.util.List'); expect(result.imports[0].names).toEqual(['List']); expect(result.imports[1].source).toBe('java.util.Map'); expect(result.imports[1].names).toEqual(['Map']); expect(result.imports[2].source).toBe('com.example.service.UserService'); expect(result.imports[2].names).toEqual(['UserService']); }); it('extracts static imports', () => { const content = `import static org.junit.Assert.assertEquals;`; const result = parseJava(content); expect(result.imports).toHaveLength(1); expect(result.imports[0].source).toBe('org.junit.Assert.assertEquals'); expect(result.imports[0].names).toEqual(['assertEquals']); }); }); describe('empty content', () => { it('handles empty content', () => { const result = parseJava(''); expect(result.functions).toEqual([]); expect(result.classes).toEqual([]); expect(result.imports).toEqual([]); expect(result.exports).toEqual([]); }); }); }); describe('parseGeneric', () => { describe('PHP patterns', () => { it('extracts PHP functions', () => { const content = ` { const content = ` { const content = ` { it('extracts Ruby methods', () => { const content = `def calculate(x, y) x + y end`; const result = parseGeneric(content); expect(result.functions).toHaveLength(1); expect(result.functions[0].name).toBe('calculate'); expect(result.functions[0].params).toEqual(['x', 'y']); }); it('extracts Ruby classes', () => { const content = `class UserService def initialize(db) @db = db end def find_user(id) @db.find(id) end end`; const result = parseGeneric(content); expect(result.classes).toHaveLength(1); expect(result.classes[0].name).toBe('UserService'); expect(result.classes[0].methods).toContain('initialize'); expect(result.classes[0].methods).toContain('find_user'); }); it('extracts Ruby require statements', () => { const content = `require 'json' require_relative 'helpers/utils'`; const result = parseGeneric(content); expect(result.imports).toHaveLength(2); expect(result.imports[0].source).toBe('json'); expect(result.imports[0].names).toEqual(['json']); expect(result.imports[1].source).toBe('helpers/utils'); expect(result.imports[1].names).toEqual(['utils']); }); }); describe('fallback behavior', () => { it('returns empty result for unrecognized content', () => { const content = `-- This is some SQL or unknown language SELECT * FROM users WHERE id = 1;`; const result = parseGeneric(content); expect(result.functions).toEqual([]); expect(result.classes).toEqual([]); expect(result.imports).toEqual([]); expect(result.exports).toEqual([]); }); it('handles empty content', () => { const result = parseGeneric(''); expect(result.functions).toEqual([]); expect(result.classes).toEqual([]); expect(result.imports).toEqual([]); expect(result.exports).toEqual([]); }); }); });