codewalker
This commit is contained in:
@@ -93,4 +93,4 @@ pub fn (e Enum) vgen() string {
|
||||
}
|
||||
|
||||
return '${comments}${prefix}enum ${e.name} {${values_str}\n}'
|
||||
}
|
||||
}
|
||||
|
||||
280
lib/core/codegenerator/codegenerator.v
Normal file
280
lib/core/codegenerator/codegenerator.v
Normal file
@@ -0,0 +1,280 @@
|
||||
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'
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
module codegenerator
|
||||
|
||||
import incubaid.herolib.core.codeparser
|
||||
|
||||
@[params]
|
||||
pub struct GeneratorOptions {
|
||||
pub:
|
||||
@@ -10,18 +12,16 @@ pub:
|
||||
}
|
||||
|
||||
pub fn new(args GeneratorOptions) !CodeGenerator {
|
||||
import incubaid.herolib.core.codeparser
|
||||
|
||||
mut parser := codeparser.new(
|
||||
path: args.parser_path
|
||||
recursive: args.recursive
|
||||
)!
|
||||
|
||||
|
||||
parser.parse()!
|
||||
|
||||
return CodeGenerator{
|
||||
parser: parser
|
||||
output_dir: args.output_dir
|
||||
format: args.format
|
||||
format: args.format
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
31
lib/core/codegenerator/markdown_gen.v
Normal file
31
lib/core/codegenerator/markdown_gen.v
Normal file
@@ -0,0 +1,31 @@
|
||||
module codegenerator
|
||||
|
||||
import incubaid.herolib.core.pathlib
|
||||
|
||||
pub struct MarkdownGenerator {
|
||||
pub mut:
|
||||
generator CodeGenerator
|
||||
output_dir string
|
||||
}
|
||||
|
||||
// write_all writes all generated markdown files to disk
|
||||
pub fn (mut mgen MarkdownGenerator) write_all() ! {
|
||||
modules := mgen.generator.parser.list_modules()
|
||||
|
||||
// Ensure output directory exists
|
||||
mut out_dir := pathlib.get_dir(path: mgen.output_dir, create: true)!
|
||||
|
||||
for module_name in modules {
|
||||
mgen.write_module(module_name)!
|
||||
}
|
||||
}
|
||||
|
||||
// write_module writes a single module's markdown to disk
|
||||
pub fn (mut mgen MarkdownGenerator) write_module(module_name string) ! {
|
||||
md := mgen.generator.module_to_markdown(module_name)!
|
||||
filename := mgen.generator.module_to_filename(module_name)
|
||||
|
||||
filepath := mgen.output_dir + '/' + filename
|
||||
mut file := pathlib.get_file(path: filepath, create: true)!
|
||||
file.write(md)!
|
||||
}
|
||||
188
lib/core/codegenerator/markdown_test.v
Normal file
188
lib/core/codegenerator/markdown_test.v
Normal file
@@ -0,0 +1,188 @@
|
||||
module codegenerator
|
||||
|
||||
import incubaid.herolib.ui.console
|
||||
import incubaid.herolib.core.codeparser
|
||||
import incubaid.herolib.core.pathlib
|
||||
import os
|
||||
|
||||
fn test_markdown_generation() {
|
||||
console.print_header('CodeGenerator Markdown Test')
|
||||
console.print_lf(1)
|
||||
|
||||
// Setup: Use the same test data as codeparser
|
||||
test_dir := setup_test_directory()
|
||||
defer {
|
||||
os.rmdir_all(test_dir) or {}
|
||||
}
|
||||
|
||||
// Create output directory
|
||||
output_dir := '/tmp/codegen_output'
|
||||
os.rmdir_all(output_dir) or {}
|
||||
os.mkdir_all(output_dir) or { panic('Failed to create output dir') }
|
||||
defer {
|
||||
os.rmdir_all(output_dir) or {}
|
||||
}
|
||||
|
||||
// Create generator
|
||||
console.print_item('Creating CodeGenerator...')
|
||||
mut gen := new(
|
||||
parser_path: test_dir
|
||||
output_dir: output_dir
|
||||
recursive: true
|
||||
)!
|
||||
|
||||
console.print_item('Parser found ${gen.parser.list_modules().len} modules')
|
||||
console.print_lf(1)
|
||||
|
||||
// Test filename conversion
|
||||
console.print_header('Test 1: Filename Conversion')
|
||||
struct TestCase {
|
||||
module_name string
|
||||
expected string
|
||||
}
|
||||
|
||||
test_cases := [
|
||||
TestCase{
|
||||
module_name: 'incubaid.herolib.core.code'
|
||||
expected: 'code.md'
|
||||
},
|
||||
TestCase{
|
||||
module_name: 'testdata'
|
||||
expected: 'testdata.md'
|
||||
},
|
||||
TestCase{
|
||||
module_name: 'testdata.services'
|
||||
expected: 'services.md'
|
||||
},
|
||||
]
|
||||
|
||||
for test_case in test_cases {
|
||||
result := gen.module_to_filename(test_case.module_name)
|
||||
assert result == test_case.expected, 'Expected ${test_case.expected}, got ${result}'
|
||||
console.print_item(' ✓ ${test_case.module_name} -> ${result}')
|
||||
}
|
||||
console.print_lf(1)
|
||||
|
||||
// Test module documentation generation
|
||||
console.print_header('Test 2: Module Documentation Generation')
|
||||
|
||||
// Get a testdata module
|
||||
modules := gen.parser.list_modules()
|
||||
testdata_modules := modules.filter(it.contains('testdata'))
|
||||
|
||||
assert testdata_modules.len > 0, 'No testdata modules found'
|
||||
|
||||
for mod_name in testdata_modules {
|
||||
console.print_item('Generating docs for: ${mod_name}')
|
||||
|
||||
md := gen.module_to_markdown(mod_name)!
|
||||
|
||||
// Validate markdown content
|
||||
assert md.len > 0, 'Generated markdown is empty'
|
||||
assert md.contains('# Module:'), 'Missing module header'
|
||||
|
||||
// List basic structure checks
|
||||
structs := gen.parser.list_structs(mod_name)
|
||||
functions := gen.parser.list_functions(mod_name)
|
||||
consts := gen.parser.list_constants(mod_name)
|
||||
|
||||
if structs.len > 0 {
|
||||
assert md.contains('## Structs'), 'Missing Structs section'
|
||||
console.print_item(' - Found ${structs.len} structs')
|
||||
}
|
||||
|
||||
if functions.len > 0 {
|
||||
assert md.contains('## Functions'), 'Missing Functions section'
|
||||
console.print_item(' - Found ${functions.len} functions')
|
||||
}
|
||||
|
||||
if consts.len > 0 {
|
||||
assert md.contains('## Constants'), 'Missing Constants section'
|
||||
console.print_item(' - Found ${consts.len} constants')
|
||||
}
|
||||
}
|
||||
console.print_lf(1)
|
||||
|
||||
// Test file writing
|
||||
console.print_header('Test 3: Write Generated Files')
|
||||
|
||||
for mod_name in testdata_modules {
|
||||
gen.generate_module(mod_name)!
|
||||
}
|
||||
|
||||
// Verify files were created
|
||||
files := os.ls(output_dir)!
|
||||
assert files.len > 0, 'No files generated'
|
||||
|
||||
console.print_item('Generated ${files.len} markdown files:')
|
||||
for file in files {
|
||||
console.print_item(' - ${file}')
|
||||
|
||||
// Verify file content
|
||||
filepath := os.join_path(output_dir, file)
|
||||
content := os.read_file(filepath)!
|
||||
assert content.len > 0, 'Generated file is empty: ${file}'
|
||||
}
|
||||
console.print_lf(1)
|
||||
|
||||
// Test content validation
|
||||
console.print_header('Test 4: Content Validation')
|
||||
|
||||
for file in files {
|
||||
filepath := os.join_path(output_dir, file)
|
||||
content := os.read_file(filepath)!
|
||||
|
||||
// Check for required sections
|
||||
has_module_header := content.contains('# Module:')
|
||||
has_imports := content.contains('## Imports') || !content.contains('import ')
|
||||
has_valid_format := content.contains('```v')
|
||||
|
||||
assert has_module_header, '${file}: Missing module header'
|
||||
assert has_valid_format || file.contains('services'), '${file}: Invalid markdown format'
|
||||
|
||||
console.print_item(' ✓ ${file}: Valid content')
|
||||
}
|
||||
console.print_lf(1)
|
||||
|
||||
console.print_green('✓ All CodeGenerator tests passed!')
|
||||
}
|
||||
|
||||
// Helper: Setup test directory (copy from codeparser test)
|
||||
fn setup_test_directory() string {
|
||||
test_dir := '/tmp/codegen_test_data'
|
||||
|
||||
os.rmdir_all(test_dir) or {}
|
||||
|
||||
current_file := @FILE
|
||||
current_dir := os.dir(current_file)
|
||||
|
||||
// Navigate to codeparser testdata
|
||||
codeparser_dir := os.join_path(os.dir(current_dir), 'codeparser')
|
||||
testdata_dir := os.join_path(codeparser_dir, 'testdata')
|
||||
|
||||
if !os.is_dir(testdata_dir) {
|
||||
panic('testdata directory not found at: ${testdata_dir}')
|
||||
}
|
||||
|
||||
os.mkdir_all(test_dir) or { panic('Failed to create test directory') }
|
||||
copy_directory(testdata_dir, test_dir) or { panic('Failed to copy testdata: ${err}') }
|
||||
|
||||
return test_dir
|
||||
}
|
||||
|
||||
fn copy_directory(src string, dst string) ! {
|
||||
entries := os.ls(src)!
|
||||
|
||||
for entry in entries {
|
||||
src_path := os.join_path(src, entry)
|
||||
dst_path := os.join_path(dst, entry)
|
||||
|
||||
if os.is_dir(src_path) {
|
||||
os.mkdir_all(dst_path)!
|
||||
copy_directory(src_path, dst_path)!
|
||||
} else {
|
||||
content := os.read_file(src_path)!
|
||||
os.write_file(dst_path, content)!
|
||||
}
|
||||
}
|
||||
}
|
||||
1
lib/core/codegenerator/templates/function.md.template
Normal file
1
lib/core/codegenerator/templates/function.md.template
Normal file
@@ -0,0 +1 @@
|
||||
fn ${func.name}(${func.params.map(it.name + ': ' + it.typ.symbol()).join(', ')}) ${func.result.typ.symbol()}
|
||||
5
lib/core/codegenerator/templates/module.md.template
Normal file
5
lib/core/codegenerator/templates/module.md.template
Normal file
@@ -0,0 +1,5 @@
|
||||
# Module: ${module_name}
|
||||
|
||||
This module provides functionality for code generation and documentation.
|
||||
|
||||
**Location:** `${module_name.replace('.', '/')}`
|
||||
2
lib/core/codegenerator/templates/struct.md.template
Normal file
2
lib/core/codegenerator/templates/struct.md.template
Normal file
@@ -0,0 +1,2 @@
|
||||
struct ${struct_.name} {
|
||||
}
|
||||
@@ -204,4 +204,4 @@ pub fn (parser CodeParser) to_json(module_name string) !string {
|
||||
}
|
||||
|
||||
return json.encode_pretty(result)
|
||||
}
|
||||
}
|
||||
|
||||
22
lib/core/generator/heromodels/ai_instructions.v
Normal file
22
lib/core/generator/heromodels/ai_instructions.v
Normal file
@@ -0,0 +1,22 @@
|
||||
module heromodels
|
||||
|
||||
import incubaid.herolib.develop.gittools
|
||||
import incubaid.herolib.core.pathlib
|
||||
|
||||
pub fn aiprompts_path() !string {
|
||||
return gittools.path(
|
||||
git_url: 'https://github.com/Incubaid/herolib/tree/development/aiprompts'
|
||||
)!.path
|
||||
}
|
||||
|
||||
pub fn ai_instructions_hero_models() !string {
|
||||
path := '${aiprompts_path()!}/ai_instructions_hero_models.md'
|
||||
mut ppath := pathlib.get_file(path: path, create: false)!
|
||||
return ppath.read()!
|
||||
}
|
||||
|
||||
pub fn ai_instructions_vlang_herolib_core() !string {
|
||||
path := '${aiprompts_path()!}/vlang_herolib_core.md'
|
||||
mut ppath := pathlib.get_file(path: path, create: false)!
|
||||
return ppath.read()!
|
||||
}
|
||||
182
lib/core/generator/heromodels/code_generator.v
Executable file
182
lib/core/generator/heromodels/code_generator.v
Executable file
@@ -0,0 +1,182 @@
|
||||
module heromodels
|
||||
|
||||
import incubaid.herolib.core.pathlib
|
||||
import incubaid.herolib.ui.console
|
||||
import incubaid.herolib.ai.client
|
||||
import os
|
||||
|
||||
pub fn do() {
|
||||
console.print_header('Code Generator - V File Analyzer Using AI')
|
||||
|
||||
// Find herolib root directory using @FILE
|
||||
script_dir := os.dir(@FILE)
|
||||
// Navigate from examples/core/code to root: up 4 levels
|
||||
herolib_root := os.dir(os.dir(os.dir(script_dir)))
|
||||
|
||||
console.print_item('HeroLib Root: ${herolib_root}')
|
||||
|
||||
// The directory we want to analyze (lib/core in this case)
|
||||
target_dir := herolib_root + '/lib/core'
|
||||
console.print_item('Target Directory: ${target_dir}')
|
||||
console.print_lf(1)
|
||||
|
||||
// Load instruction files from aiprompts
|
||||
console.print_item('Loading instruction files...')
|
||||
|
||||
mut ai_instructions_file := pathlib.get(herolib_root +
|
||||
'/aiprompts/ai_instructions_hero_models.md')
|
||||
mut vlang_core_file := pathlib.get(herolib_root + '/aiprompts/vlang_herolib_core.md')
|
||||
|
||||
ai_instructions_content := ai_instructions_file.read()!
|
||||
vlang_core_content := vlang_core_file.read()!
|
||||
|
||||
console.print_green('✓ Instruction files loaded successfully')
|
||||
console.print_lf(1)
|
||||
|
||||
// Initialize AI client
|
||||
console.print_item('Initializing AI client...')
|
||||
mut aiclient := client.new()!
|
||||
console.print_green('✓ AI client initialized')
|
||||
console.print_lf(1)
|
||||
|
||||
// Get all V files from target directory
|
||||
console.print_item('Scanning directory for V files...')
|
||||
|
||||
mut target_path := pathlib.get_dir(path: target_dir, create: false)!
|
||||
mut all_files := target_path.list(
|
||||
regex: [r'\.v$']
|
||||
recursive: true
|
||||
)!
|
||||
|
||||
console.print_item('Found ${all_files.paths.len} total V files')
|
||||
|
||||
// TODO: Walk over all files which do NOT end with _test.v and do NOT start with factory
|
||||
// Each file becomes a src_file_content object
|
||||
mut files_to_process := []pathlib.Path{}
|
||||
|
||||
for file in all_files.paths {
|
||||
file_name := file.name()
|
||||
|
||||
// Skip test files
|
||||
if file_name.ends_with('_test.v') {
|
||||
continue
|
||||
}
|
||||
|
||||
// Skip factory files
|
||||
if file_name.starts_with('factory') {
|
||||
continue
|
||||
}
|
||||
|
||||
files_to_process << file
|
||||
}
|
||||
|
||||
console.print_green('✓ After filtering: ${files_to_process.len} files to process')
|
||||
console.print_lf(2)
|
||||
|
||||
// Process each file with AI
|
||||
total_files := files_to_process.len
|
||||
|
||||
for idx, mut file in files_to_process {
|
||||
current_idx := idx + 1
|
||||
process_file_with_ai(mut aiclient, mut file, ai_instructions_content, vlang_core_content,
|
||||
current_idx, total_files)!
|
||||
}
|
||||
|
||||
console.print_lf(1)
|
||||
console.print_header('✓ Code Generation Complete')
|
||||
console.print_item('Processed ${files_to_process.len} files')
|
||||
console.print_lf(1)
|
||||
}
|
||||
|
||||
fn process_file_with_ai(mut aiclient client.AIClient, mut file pathlib.Path, ai_instructions string, vlang_core string, current int, total int) ! {
|
||||
file_name := file.name()
|
||||
src_file_path := file.absolute()
|
||||
|
||||
console.print_item('[${current}/${total}] Analyzing: ${file_name}')
|
||||
|
||||
// Read the file content - this is the src_file_content
|
||||
src_file_content := file.read()!
|
||||
|
||||
// Build comprehensive system prompt
|
||||
// TODO: Load instructions from prompt files and use in prompt
|
||||
|
||||
// Build the user prompt with context
|
||||
user_prompt := '
|
||||
File: ${file_name}
|
||||
Path: ${src_file_path}
|
||||
|
||||
Current content:
|
||||
\`\`\`v
|
||||
${src_file_content}
|
||||
\`\`\`
|
||||
|
||||
Please improve this V file by:
|
||||
1. Following V language best practices
|
||||
2. Ensuring proper error handling with ! and or blocks
|
||||
3. Adding clear documentation comments
|
||||
4. Following herolib patterns and conventions
|
||||
5. Improving code clarity and readability
|
||||
|
||||
Context from herolib guidelines:
|
||||
|
||||
VLANG HEROLIB CORE:
|
||||
${vlang_core}
|
||||
|
||||
AI INSTRUCTIONS FOR HERO MODELS:
|
||||
${ai_instructions}
|
||||
|
||||
Return ONLY the complete improved file wrapped in \`\`\`v code block.
|
||||
'
|
||||
|
||||
console.print_debug_title('Sending to AI', 'Calling AI model to improve ${file_name}...')
|
||||
|
||||
// TODO: Call AI client with model gemini-3-pro
|
||||
aiclient.write_from_prompt(file, user_prompt, [.pro]) or {
|
||||
console.print_stderr('Error processing ${file_name}: ${err}')
|
||||
return
|
||||
}
|
||||
|
||||
mut improved_file := pathlib.get(src_file_path + '.improved')
|
||||
improved_content := improved_file.read()!
|
||||
|
||||
// Display improvements summary
|
||||
sample_chars := 250
|
||||
preview := if improved_content.len > sample_chars {
|
||||
improved_content[..sample_chars] + '... (preview truncated)'
|
||||
} else {
|
||||
improved_content
|
||||
}
|
||||
|
||||
console.print_debug_title('AI Analysis Results for ${file_name}', preview)
|
||||
|
||||
// Optional: Save improved version for review
|
||||
// Uncomment to enable saving
|
||||
// improved_file_path := src_file_path + '.improved'
|
||||
// mut improved_file := pathlib.get_file(path: improved_file_path, create: true)!
|
||||
// improved_file.write(improved_content)!
|
||||
// console.print_green('✓ Improvements saved to: ${improved_file_path}')
|
||||
|
||||
console.print_lf(1)
|
||||
}
|
||||
|
||||
// Extract V code from markdown code block
|
||||
fn extract_code_block(response string) string {
|
||||
// Look for ```v ... ``` block
|
||||
start_marker := '\`\`\`v'
|
||||
end_marker := '\`\`\`'
|
||||
|
||||
start_idx := response.index(start_marker) or {
|
||||
// If no ```v, try to return as-is
|
||||
return response
|
||||
}
|
||||
|
||||
mut content_start := start_idx + start_marker.len
|
||||
if content_start < response.len && response[content_start] == `\n` {
|
||||
content_start++
|
||||
}
|
||||
|
||||
end_idx := response.index(end_marker) or { return response[content_start..] }
|
||||
|
||||
extracted := response[content_start..end_idx]
|
||||
return extracted.trim_space()
|
||||
}
|
||||
25
lib/core/generator/heromodels/templates/model_code.md
Normal file
25
lib/core/generator/heromodels/templates/model_code.md
Normal file
@@ -0,0 +1,25 @@
|
||||
File: ${file_name}
|
||||
Path: ${src_file_path}
|
||||
|
||||
Current content:
|
||||
|
||||
```v
|
||||
${src_file_content}
|
||||
```
|
||||
|
||||
Please improve this V file by:
|
||||
1. Following V language best practices
|
||||
2. Ensuring proper error handling with ! and or blocks
|
||||
3. Adding clear documentation comments
|
||||
4. Following herolib patterns and conventions
|
||||
5. Improving code clarity and readability
|
||||
|
||||
Context from herolib guidelines:
|
||||
|
||||
VLANG HEROLIB CORE:
|
||||
${vlang_core}
|
||||
|
||||
AI INSTRUCTIONS FOR HERO MODELS:
|
||||
${ai_instructions}
|
||||
|
||||
Return ONLY the complete improved file wrapped in ```v code block.
|
||||
@@ -2,7 +2,6 @@ module pathlib
|
||||
|
||||
import os
|
||||
import regex
|
||||
// import incubaid.herolib.core.smartid
|
||||
import incubaid.herolib.ui.console
|
||||
|
||||
@[params]
|
||||
@@ -38,6 +37,7 @@ pub mut:
|
||||
// example see https://github.com/incubaid/herolib/blob/development/examples/core/pathlib/examples/list/path_list.v
|
||||
//
|
||||
// e.g. p.list(regex:[r'.*\.v$'])! //notice the r in front of string, this is regex for all files ending with .v
|
||||
// e.g.
|
||||
//
|
||||
// ```
|
||||
// please note links are ignored for walking over dirstructure (for files and dirs)
|
||||
|
||||
Reference in New Issue
Block a user