mr4's picture
Upload 136 files
fd8cdf5 verified
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<String, Error> {
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<u8>,
}`;
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 = `<?php
function calculateTotal($items, $tax) {
$sum = 0;
foreach ($items as $item) {
$sum += $item;
}
return $sum * (1 + $tax);
}`;
const result = parseGeneric(content);
expect(result.functions).toHaveLength(1);
expect(result.functions[0].name).toBe('calculateTotal');
expect(result.functions[0].params).toEqual(['items', 'tax']);
});
it('extracts PHP classes', () => {
const content = `<?php
class UserController {
public function index() {
return view('users.index');
}
public function store($request) {
// store logic
}
}`;
const result = parseGeneric(content);
expect(result.classes).toHaveLength(1);
expect(result.classes[0].name).toBe('UserController');
expect(result.classes[0].methods).toContain('index');
expect(result.classes[0].methods).toContain('store');
});
it('extracts PHP use statements', () => {
const content = `<?php
use App\\Models\\User;
use Illuminate\\Http\\Request;`;
const result = parseGeneric(content);
expect(result.imports).toHaveLength(2);
expect(result.imports[0].names).toEqual(['User']);
expect(result.imports[1].names).toEqual(['Request']);
});
});
describe('Ruby patterns', () => {
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([]);
});
});
});