Files
herolib/lib/core/codegenerator/codegenerator.v
2025-11-24 05:48:13 +01:00

281 lines
6.7 KiB
V

module codegenerator
import incubaid.herolib.core.codeparser
import incubaid.herolib.core.pathlib
import incubaid.herolib.core.code
import incubaid.herolib.core.texttools
import os
pub struct CodeGenerator {
pub mut:
parser codeparser.CodeParser
output_dir string
format bool
}
// generate_all generates markdown docs for all modules
pub fn (mut gen CodeGenerator) generate_all() ! {
modules := gen.parser.list_modules()
for module_name in modules {
gen.generate_module(module_name)!
}
}
// generate_module generates markdown for a single module
pub fn (mut gen CodeGenerator) generate_module(module_name string) ! {
md := gen.module_to_markdown(module_name)!
// Convert module name to filename: incubaid.herolib.core.code -> code___core___code.md
filename := gen.module_to_filename(module_name)
filepath := os.join_path(gen.output_dir, filename)
mut file := pathlib.get_file(path: filepath, create: true)!
file.write(md)!
}
// module_to_markdown generates complete markdown for a module
pub fn (gen CodeGenerator) module_to_markdown(module_name string) !string {
module_obj := gen.parser.find_module(module_name)!
mut md := ''
// Use template for module header
md += $tmpl('templates/module.md.template')
// Imports section
imports := gen.parser.list_imports(module_name)
if imports.len > 0 {
md += gen.imports_section(imports)
}
// Constants section
consts := gen.parser.list_constants(module_name)
if consts.len > 0 {
md += gen.constants_section(consts)
}
// Structs section
structs := gen.parser.list_structs(module_name)
if structs.len > 0 {
md += gen.structs_section(structs, module_name)
}
// Functions section
functions := gen.parser.list_functions(module_name)
if functions.len > 0 {
md += gen.functions_section(functions, module_name)
}
// Interfaces section
interfaces := gen.parser.list_interfaces(module_name)
if interfaces.len > 0 {
md += gen.interfaces_section(interfaces)
}
return md
}
// imports_section generates imports documentation
fn (gen CodeGenerator) imports_section(imports []code.Import) string {
mut md := '## Imports\n\n'
for imp in imports {
md += '- `' + imp.mod + '`\n'
}
md += '\n'
return md
}
// constants_section generates constants documentation
fn (gen CodeGenerator) constants_section(consts []code.Const) string {
mut md := '## Constants\n\n'
for const_ in consts {
md += '- `' + const_.name + '` = `' + const_.value + '`\n'
}
md += '\n'
return md
}
// structs_section generates structs documentation
fn (gen CodeGenerator) structs_section(structs []code.Struct, module_name string) string {
mut md := '## Structs\n\n'
for struct_ in structs {
md += gen.struct_to_markdown(struct_)
}
return md
}
// functions_section generates functions documentation
fn (gen CodeGenerator) functions_section(functions []code.Function, module_name string) string {
mut md := '## Functions & Methods\n\n'
// Separate regular functions and methods
regular_functions := functions.filter(it.receiver.typ.symbol() == '')
methods := functions.filter(it.receiver.typ.symbol() != '')
// Regular functions
if regular_functions.len > 0 {
md += '### Functions\n\n'
for func in regular_functions {
md += gen.function_to_markdown(func)
}
}
// Methods (grouped by struct)
if methods.len > 0 {
md += '### Methods\n\n'
structs := gen.parser.list_structs(module_name)
for struct_ in structs {
struct_methods := methods.filter(it.receiver.typ.symbol().contains(struct_.name))
if struct_methods.len > 0 {
md += '#### ' + struct_.name + '\n\n'
for method in struct_methods {
md += gen.function_to_markdown(method)
}
}
}
}
return md
}
// interfaces_section generates interfaces documentation
fn (gen CodeGenerator) interfaces_section(interfaces []code.Interface) string {
mut md := '## Interfaces\n\n'
for iface in interfaces {
md += '### ' + iface.name + '\n\n'
if iface.description != '' {
md += iface.description + '\n\n'
}
md += '```v\n'
if iface.is_pub {
md += 'pub '
}
md += 'interface ' + iface.name + ' {\n'
for field in iface.fields {
md += ' ' + field.name + ': ' + field.typ.symbol() + '\n'
}
md += '}\n```\n\n'
}
return md
}
// struct_to_markdown converts struct to markdown
fn (gen CodeGenerator) struct_to_markdown(struct_ code.Struct) string {
mut md := '### '
if struct_.is_pub {
md += '**pub** '
}
md += 'struct ' + struct_.name + '\n\n'
if struct_.description != '' {
md += struct_.description + '\n\n'
}
md += '```v\n'
if struct_.is_pub {
md += 'pub '
}
md += 'struct ' + struct_.name + ' {\n'
for field in struct_.fields {
md += ' ' + field.name + ' ' + field.typ.symbol() + '\n'
}
md += '}\n'
md += '```\n\n'
// Field documentation
if struct_.fields.len > 0 {
md += '**Fields:**\n\n'
for field in struct_.fields {
visibility := if field.is_pub { 'public' } else { 'private' }
mutability := if field.is_mut { ', mutable' } else { '' }
md += '- `' + field.name + '` (`' + field.typ.symbol() + '`)' + mutability + ' - ' +
visibility + '\n'
if field.description != '' {
md += ' - ' + field.description + '\n'
}
}
md += '\n'
}
return md
}
// function_to_markdown converts function to markdown
fn (gen CodeGenerator) function_to_markdown(func code.Function) string {
mut md := ''
// Function signature
signature := gen.function_signature(func)
md += '- `' + signature + '`\n'
// Description
if func.description != '' {
md += ' - *' + func.description + '*\n'
}
// Parameters
if func.params.len > 0 {
md += '\n **Parameters:**\n'
for param in func.params {
md += ' - `' + param.name + '` (`' + param.typ.symbol() + '`)'
if param.description != '' {
md += ' - ' + param.description
}
md += '\n'
}
}
// Return type
if func.result.typ.symbol() != '' {
md += '\n **Returns:** `' + func.result.typ.symbol() + '`\n'
}
md += '\n'
return md
}
// function_signature generates a function signature string
fn (gen CodeGenerator) function_signature(func code.Function) string {
mut sig := if func.is_pub { 'pub ' } else { '' }
if func.receiver.name != '' {
sig += '(' + func.receiver.name + ' ' + func.receiver.typ.symbol() + ') '
}
sig += func.name
// Parameters
params := func.params.map(it.name + ': ' + it.typ.symbol()).join(', ')
sig += '(' + params + ')'
// Return type
if func.result.typ.symbol() != '' {
sig += ' -> ' + func.result.typ.symbol()
}
return sig
}
// module_to_filename converts module name to filename
// e.g., incubaid.herolib.core.code -> code__core__code.md
pub fn (gen CodeGenerator) module_to_filename(module_name string) string {
// Get last part after last dot, then add __ and rest in reverse
parts := module_name.split('.')
filename := parts[parts.len - 1]
return filename + '.md'
}