rename: archdoc → wtismycode (WTIsMyCode)

This commit is contained in:
2026-02-15 12:12:33 +03:00
parent 136697caf0
commit f4f8b8fa34
87 changed files with 244 additions and 212 deletions

View File

@@ -0,0 +1,60 @@
# Architecture Documentation
Generated at: 1970-01-01 00:00:00 UTC
## Overview
This document provides an overview of the architecture for the project.
## Modules
### example.py
File: `example.py`
#### Imports
- `os`
- `typing.List`
#### Symbols
##### Calculator
- Type: Class
- Signature: `class Calculator`
- Purpose: extracted from AST
##### Calculator.__init__
- Type: Function
- Signature: `def __init__(...)`
- Purpose: extracted from AST
##### Calculator.add
- Type: Function
- Signature: `def add(...)`
- Purpose: extracted from AST
##### Calculator.multiply
- Type: Function
- Signature: `def multiply(...)`
- Purpose: extracted from AST
##### process_numbers
- Type: Function
- Signature: `def process_numbers(...)`
- Purpose: extracted from AST
## Metrics
### Critical Components
No critical components identified.
### Component Dependencies
Dependency analysis not yet implemented.

View File

@@ -0,0 +1,107 @@
//! Golden tests for WTIsMyCode
//!
//! These tests generate documentation for test projects and compare the output
//! with expected "golden" files to ensure consistency.
mod test_utils;
use std::fs;
use std::path::Path;
use wtismycode_core::{Config, scanner::FileScanner, python_analyzer::PythonAnalyzer};
#[test]
fn test_simple_project_generation() {
// Print current directory for debugging
let current_dir = std::env::current_dir().unwrap();
println!("Current directory: {:?}", current_dir);
// Try different paths for the config file
let possible_paths = [
"tests/golden/test_project/wtismycode.toml",
"../tests/golden/test_project/wtismycode.toml",
];
let config_path = possible_paths.iter().find(|&path| {
Path::new(path).exists()
}).expect("Could not find config file in any expected location");
println!("Using config path: {:?}", config_path);
let config = Config::load_from_file(Path::new(config_path)).expect("Failed to load config");
// Initialize scanner with the correct root path
let project_root = Path::new("tests/golden/test_project");
let scanner = FileScanner::new(config.clone());
// Scan for Python files
let python_files = scanner.scan_python_files(project_root)
.expect("Failed to scan Python files");
println!("Found Python files: {:?}", python_files);
// Initialize Python analyzer
let analyzer = PythonAnalyzer::new(config.clone());
// Parse each Python file
let mut parsed_modules = Vec::new();
for file_path in python_files {
println!("Parsing file: {:?}", file_path);
match analyzer.parse_module(&file_path) {
Ok(module) => {
println!("Successfully parsed module: {:?}", module.module_path);
println!("Imports: {:?}", module.imports);
println!("Symbols: {:?}", module.symbols.len());
println!("Calls: {:?}", module.calls.len());
parsed_modules.push(module);
},
Err(e) => {
panic!("Failed to parse {}: {}", file_path.display(), e);
}
}
}
println!("Parsed {} modules", parsed_modules.len());
// Resolve symbols and build project model
let project_model = analyzer.resolve_symbols(&parsed_modules)
.expect("Failed to resolve symbols");
println!("Project model modules: {}", project_model.modules.len());
println!("Project model files: {}", project_model.files.len());
println!("Project model symbols: {}", project_model.symbols.len());
// Add assertions to verify the project model
assert!(!project_model.modules.is_empty());
assert!(!project_model.files.is_empty());
assert!(!project_model.symbols.is_empty());
// Check specific details about the parsed modules
// Now we have 2 modules (example.py and advanced_example.py)
assert_eq!(project_model.modules.len(), 2);
// Find the example.py module
let mut found_example_module = false;
for (_, module) in project_model.modules.iter() {
if module.path.contains("example.py") {
found_example_module = true;
break;
}
}
assert!(found_example_module);
// Check that we found the Calculator class
let calculator_symbol = project_model.symbols.values().find(|s| s.id.ends_with("::Calculator"));
assert!(calculator_symbol.is_some());
assert_eq!(calculator_symbol.unwrap().kind, wtismycode_core::model::SymbolKind::Class);
// Check that we found the process_numbers function
let process_numbers_symbol = project_model.symbols.values().find(|s| s.id.ends_with("::process_numbers"));
assert!(process_numbers_symbol.is_some());
assert_eq!(process_numbers_symbol.unwrap().kind, wtismycode_core::model::SymbolKind::Function);
// Check file imports
assert!(!project_model.files.is_empty());
let file_entry = project_model.files.iter().next().unwrap();
let file_doc = file_entry.1;
assert!(!file_doc.imports.is_empty());
}

View File

@@ -0,0 +1,73 @@
# ARCHITECTURE — New Project
<!-- MANUAL:BEGIN -->
## Project summary
**Name:** New Project
**Description:** <FILL_MANUALLY: what this project does in 37 lines>
## Key decisions (manual)
- <FILL_MANUALLY>
## Non-goals (manual)
- <FILL_MANUALLY>
<!-- MANUAL:END -->
---
## Document metadata
- **Created:** 2026-01-25
- **Updated:** 2026-01-25
- **Generated by:** wtismycode (cli) v0.1
---
## Rails / Tooling
<!-- ARCHDOC:BEGIN section=rails -->
No tooling information available.
<!-- ARCHDOC:END section=rails -->
---
## Repository layout (top-level)
<!-- ARCHDOC:BEGIN section=layout -->
| Path | Purpose | Link |
|------|---------|------|
| ./src/advanced_example.py | Source file | [details](docs/architecture/files/._src_advanced_example.py.md) |
| ./src/example.py | Source file | [details](docs/architecture/files/._src_example.py.md) |
<!-- ARCHDOC:END section=layout -->
---
## Modules index
<!-- ARCHDOC:BEGIN section=modules_index -->
| Module | Symbols | Inbound | Outbound | Link |
|--------|---------|---------|----------|------|
| ./src/advanced_example.py | 10 | 0 | 0 | [details](docs/architecture/modules/._src_advanced_example.py.md) |
| ./src/example.py | 5 | 0 | 0 | [details](docs/architecture/modules/._src_example.py.md) |
<!-- ARCHDOC:END section=modules_index -->
---
## Critical dependency points
<!-- ARCHDOC:BEGIN section=critical_points -->
### High Fan-in (Most Called)
| Symbol | Fan-in | Critical |
|--------|--------|----------|
### High Fan-out (Calls Many)
| Symbol | Fan-out | Critical |
|--------|---------|----------|
### Module Cycles
<!-- ARCHDOC:END section=critical_points -->
---
<!-- MANUAL:BEGIN -->
## Change notes (manual)
- <FILL_MANUALLY>
<!-- MANUAL:END -->

View File

@@ -0,0 +1,3 @@
# File: ./src/advanced_example.py
TODO: Add file documentation

View File

@@ -0,0 +1,3 @@
# File: ./src/example.py
TODO: Add file documentation

View File

@@ -0,0 +1,3 @@
# Module: ./src/advanced_example.py
TODO: Add module documentation

View File

@@ -0,0 +1,3 @@
# Module: ./src/example.py
TODO: Add module documentation

View File

@@ -0,0 +1,107 @@
"""Advanced example module for testing with integrations."""
import requests
import sqlite3
import redis
from typing import List, Dict
class UserService:
"""A service for managing users with database integration."""
def __init__(self, db_path: str = "users.db"):
"""Initialize the user service with database path."""
self.db_path = db_path
self._init_db()
def _init_db(self):
"""Initialize the database."""
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL
)
""")
conn.commit()
conn.close()
def create_user(self, name: str, email: str) -> Dict:
"""Create a new user in the database."""
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute(
"INSERT INTO users (name, email) VALUES (?, ?)",
(name, email)
)
user_id = cursor.lastrowid
conn.commit()
conn.close()
return {"id": user_id, "name": name, "email": email}
def get_user(self, user_id: int) -> Dict:
"""Get a user by ID from the database."""
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,))
row = cursor.fetchone()
conn.close()
if row:
return {"id": row[0], "name": row[1], "email": row[2]}
return None
class NotificationService:
"""A service for sending notifications with queue integration."""
def __init__(self, redis_url: str = "redis://localhost:6379"):
"""Initialize the notification service with Redis URL."""
self.redis_client = redis.Redis.from_url(redis_url)
def send_email_notification(self, user_id: int, message: str) -> bool:
"""Send an email notification by queuing it."""
notification = {
"user_id": user_id,
"message": message,
"type": "email"
}
# Push to Redis queue
self.redis_client.lpush("notifications", str(notification))
return True
def fetch_external_user_data(user_id: int) -> Dict:
"""Fetch user data from an external API."""
response = requests.get(f"https://api.example.com/users/{user_id}")
if response.status_code == 200:
return response.json()
return {}
def process_users(user_ids: List[int]) -> List[Dict]:
"""Process a list of users with various integrations."""
# Database integration
user_service = UserService()
# Queue integration
notification_service = NotificationService()
results = []
for user_id in user_ids:
# Database operation
user = user_service.get_user(user_id)
if user:
# External API integration
external_data = fetch_external_user_data(user_id)
user.update(external_data)
# Queue operation
notification_service.send_email_notification(
user_id,
f"Processing user {user['name']}"
)
results.append(user)
return results

View File

@@ -0,0 +1,29 @@
"""Example module for testing."""
import os
from typing import List
class Calculator:
"""A simple calculator class."""
def __init__(self):
"""Initialize the calculator."""
pass
def add(self, a: int, b: int) -> int:
"""Add two numbers."""
return a + b
def multiply(self, a: int, b: int) -> int:
"""Multiply two numbers."""
return a * b
def process_numbers(numbers: List[int]) -> List[int]:
"""Process a list of numbers."""
calc = Calculator()
return [calc.add(n, 1) for n in numbers]
if __name__ == "__main__":
numbers = [1, 2, 3, 4, 5]
result = process_numbers(numbers)
print(f"Processed numbers: {result}")

View File

@@ -0,0 +1,62 @@
[project]
root = "."
out_dir = "docs/architecture"
entry_file = "ARCHITECTURE.md"
language = "python"
[scan]
include = ["src", "app", "tests"]
exclude = [
".venv", "venv", "__pycache__", ".git", "dist", "build",
".mypy_cache", ".ruff_cache", ".pytest_cache", "*.egg-info"
]
follow_symlinks = false
max_file_size = "10MB"
[python]
src_roots = ["src", "."]
include_tests = true
parse_docstrings = true
max_parse_errors = 10
[analysis]
resolve_calls = true
resolve_inheritance = false
detect_integrations = true
integration_patterns = [
{ type = "http", patterns = ["requests", "httpx", "aiohttp"] },
{ type = "db", patterns = ["sqlalchemy", "psycopg", "mysql", "sqlite3"] },
{ type = "queue", patterns = ["celery", "kafka", "pika", "redis"] }
]
[output]
single_file = false
per_file_docs = true
create_directories = true
overwrite_manual_sections = false
[diff]
update_timestamp_on_change_only = true
hash_algorithm = "sha256"
preserve_manual_content = true
[thresholds]
critical_fan_in = 20
critical_fan_out = 20
high_complexity = 50
[rendering]
template_engine = "handlebars"
max_table_rows = 100
truncate_long_descriptions = true
description_max_length = 200
[logging]
level = "info"
file = "wtismycode.log"
format = "compact"
[caching]
enabled = true
cache_dir = ".wtismycode/cache"
max_cache_age = "24h"

View File

@@ -0,0 +1,21 @@
//! Test utilities for golden tests
use std::fs;
use std::path::Path;
/// Read a file and return its contents
pub fn read_test_file(path: &str) -> String {
fs::read_to_string(path).expect(&format!("Failed to read test file: {}", path))
}
/// Write content to a file for testing
pub fn write_test_file(path: &str, content: &str) {
fs::write(path, content).expect(&format!("Failed to write test file: {}", path))
}
/// Compare two strings and panic if they don't match
pub fn assert_strings_equal(actual: &str, expected: &str, message: &str) {
if actual != expected {
panic!("{}: Strings do not match\nActual:\n{}\nExpected:\n{}", message, actual, expected);
}
}