fix example compilation

This commit is contained in:
Timur Gordon
2025-03-17 01:14:04 +01:00
parent ea0637423e
commit bd3abade55
26 changed files with 45 additions and 883 deletions

View File

@@ -24,7 +24,7 @@ import net.http
// pub fn ts_client_get_fn(object string, params TSClientFunctionParams) string {
// name_snake := texttools.snake_case(object)
// name_pascal := texttools.name_fix_pascal(object)
// name_pascal := texttools.pascal_case(object)
// root := get_endpoint_root(params.endpoint)
// return "async get${name_pascal}(id: string): Promise<${name_pascal}> {\n return this.restClient.get<${name_pascal}>(`/${root}/${name_snake}/\${id}`);\n }"
@@ -32,7 +32,7 @@ import net.http
// pub fn ts_client_set_fn(object string, params TSClientFunctionParams) string {
// name_snake := texttools.snake_case(object)
// name_pascal := texttools.name_fix_pascal(object)
// name_pascal := texttools.pascal_case(object)
// root := get_endpoint_root(params.endpoint)
// return "async set${name_pascal}(id: string, ${name_snake}: Partial<${name_pascal}>): Promise<${name_pascal}> {\n return this.restClient.put<${name_pascal}>(`/${root}/${name_snake}/\${id}`, ${name_snake});\n }"
@@ -40,7 +40,7 @@ import net.http
// pub fn ts_client_delete_fn(object string, params TSClientFunctionParams) string {
// name_snake := texttools.snake_case(object)
// name_pascal := texttools.name_fix_pascal(object)
// name_pascal := texttools.pascal_case(object)
// root := get_endpoint_root(params.endpoint)
// return "async delete${name_pascal}(id: string): Promise<void> {\n return this.restClient.delete<void>(`/${root}/${name_snake}/\${id}`);\n }"
@@ -48,7 +48,7 @@ import net.http
// pub fn ts_client_list_fn(object string, params TSClientFunctionParams) string {
// name_snake := texttools.snake_case(object)
// name_pascal := texttools.name_fix_pascal(object)
// name_pascal := texttools.pascal_case(object)
// root := get_endpoint_root(params.endpoint)
// return "async list${name_pascal}(): Promise<${name_pascal}[]> {\n return this.restClient.get<${name_pascal}[]>(`/${root}/${name_snake}`);\n }"
@@ -65,7 +65,7 @@ fn get_endpoint_root(root string) string {
// // generates a Base Object's `create` method
// pub fn ts_client_new_fn(object string, params TSClientFunctionParams) string {
// name_snake := texttools.snake_case(object)
// name_pascal := texttools.name_fix_pascal(object)
// name_pascal := texttools.pascal_case(object)
// root := get_endpoint_root(params.endpoint)
// return "async create${name_snake}(object: Omit<${name_pascal}, 'id'>): Promise<${name_pascal}> {
@@ -75,7 +75,7 @@ fn get_endpoint_root(root string) string {
// pub fn ts_client_get_fn(object string, params TSClientFunctionParams) string {
// name_snake := texttools.snake_case(object)
// name_pascal := texttools.name_fix_pascal(object)
// name_pascal := texttools.pascal_case(object)
// root := get_endpoint_root(params.endpoint)
// return "async get${name_pascal}(id: string): Promise<${name_pascal}> {\n return this.restClient.get<${name_pascal}>(`/${root}/${name_snake}/\${id}`);\n }"
@@ -83,7 +83,7 @@ fn get_endpoint_root(root string) string {
// pub fn ts_client_set_fn(object string, params TSClientFunctionParams) string {
// name_snake := texttools.snake_case(object)
// name_pascal := texttools.name_fix_pascal(object)
// name_pascal := texttools.pascal_case(object)
// root := get_endpoint_root(params.endpoint)
// return "async set${name_pascal}(id: string, ${name_snake}: Partial<${name_pascal}>): Promise<${name_pascal}> {\n return this.restClient.put<${name_pascal}>(`/${root}/${name_snake}/\${id}`, ${name_snake});\n }"
@@ -91,7 +91,7 @@ fn get_endpoint_root(root string) string {
// pub fn ts_client_delete_fn(object string, params TSClientFunctionParams) string {
// name_snake := texttools.snake_case(object)
// name_pascal := texttools.name_fix_pascal(object)
// name_pascal := texttools.pascal_case(object)
// root := get_endpoint_root(params.endpoint)
// return "async delete${name_pascal}(id: string): Promise<void> {\n return this.restClient.delete<void>(`/${root}/${name_snake}/\${id}`);\n }"
@@ -99,7 +99,7 @@ fn get_endpoint_root(root string) string {
// pub fn ts_client_list_fn(object string, params TSClientFunctionParams) string {
// name_snake := texttools.snake_case(object)
// name_pascal := texttools.name_fix_pascal(object)
// name_pascal := texttools.pascal_case(object)
// root := get_endpoint_root(params.endpoint)
// return "async list${name_pascal}(): Promise<${name_pascal}[]> {\n return this.restClient.get<${name_pascal}[]>(`/${root}/${name_snake}`);\n }"
@@ -107,7 +107,7 @@ fn get_endpoint_root(root string) string {
// // generates a function prototype given an `ActorMethod`
// pub fn ts_client_fn_prototype(method ActorMethod) string {
// name := texttools.name_fix_pascal(method.name)
// name := texttools.pascal_case(method.name)
// params := method.parameters
// .map(content_descriptor_to_parameter(it) or {panic(err)})
// .map(it.typescript())

View File

@@ -10,7 +10,7 @@ const id_param = Param{
}
// pub fn generate_object_code(actor Struct, object BaseObject) VFile {
// obj_name := texttools.name_fix_pascal_to_snake(object.structure.name)
// obj_name := texttools.snake_case(object.structure.name)
// object_type := object.structure.name
// mut items := []CodeItem{}
@@ -47,7 +47,7 @@ const id_param = Param{
// // generate_object_methods generates CRUD actor methods for a provided structure
// fn generate_get_method(actor Struct, object BaseObject) Function {
// object_name := texttools.name_fix_pascal_to_snake(object.structure.name)
// object_name := texttools.snake_case(object.structure.name)
// object_type := object.structure.name
// get_method := Function{
@@ -71,7 +71,7 @@ const id_param = Param{
// // generate_object_methods generates CRUD actor methods for a provided structure
// fn generate_set_method(actor Struct, object BaseObject) Function {
// object_name := texttools.name_fix_pascal_to_snake(object.structure.name)
// object_name := texttools.snake_case(object.structure.name)
// object_type := object.structure.name
// param_getters := generate_param_getters(
@@ -107,7 +107,7 @@ const id_param = Param{
// // generate_object_methods generates CRUD actor methods for a provided structure
// fn generate_delete_method(actor Struct, object BaseObject) Function {
// object_name := texttools.name_fix_pascal_to_snake(object.structure.name)
// object_name := texttools.snake_case(object.structure.name)
// object_type := object.structure.name
// body := 'actor.backend.delete[${object_type}](id)!'
@@ -132,7 +132,7 @@ const id_param = Param{
// // generate_object_methods generates CRUD actor methods for a provided structure
// fn generate_new_method(actor Struct, object BaseObject) Function {
// object_name := texttools.name_fix_pascal_to_snake(object.structure.name)
// object_name := texttools.snake_case(object.structure.name)
// object_type := object.structure.name
// param_getters := generate_param_getters(
@@ -172,7 +172,7 @@ const id_param = Param{
// // generate_object_methods generates CRUD actor methods for a provided structure
// fn generate_list_result_struct(actor Struct, object BaseObject) Struct {
// object_name := texttools.name_fix_pascal_to_snake(object.structure.name)
// object_name := texttools.snake_case(object.structure.name)
// object_type := object.structure.name
// return Struct{
// name: '${object_type}List'
@@ -190,7 +190,7 @@ const id_param = Param{
// // generate_object_methods generates CRUD actor methods for a provided structure
// fn generate_list_method(actor Struct, object BaseObject) Function {
// object_name := texttools.name_fix_pascal_to_snake(object.structure.name)
// object_name := texttools.snake_case(object.structure.name)
// object_type := object.structure.name
// list_struct := Struct{
@@ -234,7 +234,7 @@ const id_param = Param{
// }
// fn generate_filter_params(actor Struct, object BaseObject) []Struct {
// object_name := texttools.name_fix_pascal_to_snake(object.structure.name)
// object_name := texttools.snake_case(object.structure.name)
// object_type := object.structure.name
// return [
@@ -264,7 +264,7 @@ const id_param = Param{
// // generate_object_methods generates CRUD actor methods for a provided structure
// fn generate_filter_method(actor Struct, object BaseObject) Function {
// object_name := texttools.name_fix_pascal_to_snake(object.structure.name)
// object_name := texttools.snake_case(object.structure.name)
// object_type := object.structure.name
// param_getters := generate_param_getters(
@@ -304,7 +304,7 @@ const id_param = Param{
// // // generate_object_methods generates CRUD actor methods for a provided structure
// // fn generate_object_methods(actor Struct, object BaseObject) []Function {
// // object_name := texttools.name_fix_pascal_to_snake(object.structure.name)
// // object_name := texttools.snake_case(object.structure.name)
// // object_type := object.structure.name
// // mut funcs := []Function{}

View File

@@ -23,7 +23,7 @@ import freeflowuniverse.herolib.core.texttools
// }
// actor_name := texttools.name_fix(actor.name)
// object_name := texttools.name_fix_pascal_to_snake(object.schema.name)
// object_name := texttools.snake_case(object.schema.name)
// object_type := object.structure.name
// // TODO: support modules outside of crystal
@@ -58,7 +58,7 @@ import freeflowuniverse.herolib.core.texttools
// // generate_object_methods generates CRUD actor methods for a provided structure
// fn generate_new_method_test(actor Struct, object BaseObject) !Function {
// object_name := texttools.name_fix_pascal_to_snake(object.structure.name)
// object_name := texttools.snake_case(object.structure.name)
// object_type := object.structure.name
// required_fields := object.structure.fields.filter(it.attrs.any(it.name == 'required'))
@@ -86,7 +86,7 @@ import freeflowuniverse.herolib.core.texttools
// // generate_object_methods generates CRUD actor methods for a provided structure
// fn generate_get_method_test(actor Struct, object BaseObject) !Function {
// object_name := texttools.name_fix_pascal_to_snake(object.structure.name)
// object_name := texttools.snake_case(object.structure.name)
// object_type := object.structure.name
// required_fields := object.structure.fields.filter(it.attrs.any(it.name == 'required'))
@@ -112,7 +112,7 @@ import freeflowuniverse.herolib.core.texttools
// // generate_object_methods generates CRUD actor methods for a provided structure
// fn generate_filter_test(actor Struct, object BaseObject) !Function {
// object_name := texttools.name_fix_pascal_to_snake(object.structure.name)
// object_name := texttools.snake_case(object.structure.name)
// object_type := object.structure.name
// index_fields := object.structure.fields.filter(it.attrs.any(it.name == 'index'))

View File

@@ -24,7 +24,7 @@ fn generate_handle_file(spec ActorSpecification) !VFile {
}
pub fn generate_handle_function(spec ActorSpecification) string {
actor_name_pascal := texttools.snake_case_to_pascal(spec.name)
actor_name_pascal := texttools.pascal_case(spec.name)
mut operation_handlers := []string{}
mut routes := []string{}
@@ -54,7 +54,7 @@ pub fn generate_handle_function(spec ActorSpecification) string {
}
pub fn generate_method_handle(actor_name string, method ActorMethod) !Function {
actor_name_pascal := texttools.snake_case_to_pascal(actor_name)
actor_name_pascal := texttools.pascal_case(actor_name)
name_fixed := texttools.snake_case(method.name)
mut body := ''
if method.parameters.len == 1 {
@@ -89,7 +89,7 @@ fn method_is_void(method ActorMethod) !bool {
}
pub fn generate_example_method_handle(actor_name string, method ActorMethod) !Function {
actor_name_pascal := texttools.snake_case_to_pascal(actor_name)
actor_name_pascal := texttools.pascal_case(actor_name)
name_fixed := texttools.snake_case(method.name)
body := if !method_is_void(method)! {
if method.example.result is Example {

View File

@@ -73,7 +73,7 @@ fn generate_actor_file(spec ActorSpecification) !VFile {
dollar := '$'
version := spec.version
name_snake := texttools.snake_case(spec.name)
name_pascal := texttools.snake_case_to_pascal(spec.name)
name_pascal := texttools.pascal_case(spec.name)
actor_code := $tmpl('./templates/actor.v.template')
return VFile {
name: 'actor'
@@ -84,7 +84,7 @@ fn generate_actor_file(spec ActorSpecification) !VFile {
fn generate_actor_test_file(spec ActorSpecification) !VFile {
dollar := '$'
actor_name_snake := texttools.snake_case(spec.name)
actor_name_pascal := texttools.snake_case_to_pascal(spec.name)
actor_name_pascal := texttools.pascal_case(spec.name)
actor_test_code := $tmpl('./templates/actor_test.v.template')
return VFile {
name: 'actor_test'
@@ -97,7 +97,7 @@ fn generate_specs_file(name string, interfaces []ActorInterface) !VFile {
support_openapi := ActorInterface.openapi in interfaces
dollar := '$'
actor_name_snake := texttools.snake_case(name)
actor_name_pascal := texttools.snake_case_to_pascal(name)
actor_name_pascal := texttools.pascal_case(name)
actor_code := $tmpl('./templates/specifications.v.template')
return VFile {
name: 'specifications'

View File

@@ -8,7 +8,7 @@ import freeflowuniverse.herolib.baobab.specification {ActorMethod, ActorSpecific
pub fn generate_client_file(spec ActorSpecification) !VFile {
actor_name_snake := texttools.snake_case(spec.name)
actor_name_pascal := texttools.snake_case_to_pascal(spec.name)
actor_name_pascal := texttools.pascal_case(spec.name)
mut items := []CodeItem{}
@@ -47,7 +47,7 @@ pub fn generate_client_file(spec ActorSpecification) !VFile {
pub fn generate_example_client_file(spec ActorSpecification) !VFile {
actor_name_snake := texttools.snake_case(spec.name)
actor_name_pascal := texttools.snake_case_to_pascal(spec.name)
actor_name_pascal := texttools.pascal_case(spec.name)
mut items := []CodeItem{}

View File

@@ -12,7 +12,7 @@ const crud_prefixes = ['new', 'get', 'set', 'delete', 'list']
pub fn generate_methods_file(spec ActorSpecification) !VFile {
name_snake := texttools.snake_case(spec.name)
actor_name_pascal := texttools.snake_case_to_pascal(spec.name)
actor_name_pascal := texttools.pascal_case(spec.name)
receiver := generate_methods_receiver(spec.name)
receiver_param := Param {

View File

@@ -7,7 +7,7 @@ import freeflowuniverse.herolib.baobab.specification {ActorMethod, ActorSpecific
pub fn generate_model_file(spec ActorSpecification) !VFile {
actor_name_snake := texttools.snake_case(spec.name)
actor_name_pascal := texttools.snake_case_to_pascal(spec.name)
actor_name_pascal := texttools.pascal_case(spec.name)
return VFile {
name: 'model'

View File

@@ -87,7 +87,7 @@ pub fn from_openrpc(spec OpenRPC) !ActorSpecification {
if schema.typ == 'object' {
objects << BaseObject{
schema: Schema {...schema,
title: texttools.name_fix_pascal(key)
title: texttools.pascal_case(key)
id: texttools.snake_case(key)
}
}

View File

@@ -1,9 +1,4 @@
module code
pub struct Example {
function Function
values map[string]Value
result Value
}
pub type Value = string

View File

@@ -1,30 +0,0 @@
module code
import freeflowuniverse.herolib.core.pathlib
import os
pub interface IFile {
write(string, WriteOptions) !
name string
}
pub struct File {
pub mut:
name string
extension string
content string
}
pub fn (f File) write(path string, params WriteOptions) ! {
mut fd_file := pathlib.get_file(path: '${path}/${f.name}.${f.extension}')!
fd_file.write(f.content)!
if f.extension == 'ts' {
return f.typescript(path, params)
}
}
pub fn (f File) typescript(path string, params WriteOptions) ! {
if params.format {
os.execute('npx prettier --write ${path}')
}
}

View File

@@ -1,124 +0,0 @@
module code
import freeflowuniverse.herolib.core.texttools
pub struct Function {
pub:
name string @[omitempty]
receiver Param @[omitempty]
is_pub bool @[omitempty]
mod string @[omitempty]
pub mut:
summary string @[omitempty]
description string @[omitempty]
params []Param @[omitempty]
body string @[omitempty]
result Param @[omitempty]
has_return bool @[omitempty]
}
// vgen_function generates a function statement for a function
pub fn (function Function) vgen(options WriteOptions) string {
mut params_ := function.params.clone()
optionals := function.params.filter(it.is_optional)
options_struct := Struct{
name: '${texttools.snake_case_to_pascal(function.name)}Options'
attrs: [Attribute{
name: 'params'
}]
fields: optionals.map(StructField{
name: it.name
description: it.description
typ: it.typ
})
}
if optionals.len > 0 {
params_ << Param{
name: 'options'
typ: type_from_symbol(options_struct.name)
}
}
params := params_.filter(!it.is_optional).map(it.vgen()).join(', ')
receiver_ := Param{
...function.receiver,
typ: if function.receiver.typ is Result {
function.receiver.typ.typ
} else {function.receiver.typ}
}
receiver := if receiver_.vgen().trim_space() != '' {
'(${receiver_.vgen()})'
} else {''}
name := texttools.name_fix(function.name)
result := function.result.typ.vgen()
mut function_str := $tmpl('templates/function/function.v.template')
// if options.format {
// result := os.execute_opt('echo "${function_str.replace('$', '\\$')}" | v fmt') or {
// panic('${function_str}\n${err}')
// }
// function_str = result.output
// }
function_str = function_str.split_into_lines().filter(!it.starts_with('import ')).join('\n')
return if options_struct.fields.len != 0 {
'${options_struct.vgen()}\n${function_str}'
} else {
function_str
}
}
pub fn new_function(code string) !Function {
// TODO: implement function from file line
return parse_function(code)!
}
pub fn parse_function(code_ string) !Function {
mut code := code_.trim_space()
is_pub := code.starts_with('pub ')
if is_pub {
code = code.trim_string_left('pub ').trim_space()
}
is_fn := code.starts_with('fn ')
if !is_fn {
return error('invalid function format')
}
code = code.trim_string_left('fn ').trim_space()
receiver := if code.starts_with('(') {
param_str := code.all_after('(').all_before(')').trim_space()
code = code.all_after(')').trim_space()
parse_param(param_str)!
} else {
Param{}
}
name := code.all_before('(').trim_space()
code = code.trim_string_left(name).trim_space()
params_str := code.all_after('(').all_before(')')
params := if params_str.trim_space() != '' {
params_str_lst := params_str.split(',')
params_str_lst.map(parse_param(it)!)
} else {
[]Param{}
}
result := new_param(
v: code.all_after(')').all_before('{').replace(' ', '')
)!
body := if code.contains('{') { code.all_after('{').all_before_last('}') } else { '' }
return Function{
name: name
receiver: receiver
params: params
result: result
body: body
}
}

View File

@@ -6,4 +6,4 @@ pub struct Example {
result Value
}
pub type Value = string
// pub type Value = string

View File

@@ -4,8 +4,6 @@ import freeflowuniverse.herolib.core.texttools
import freeflowuniverse.herolib.core.pathlib
import os
<<<<<<<< HEAD:lib/core/code/vfile.v
========
pub interface IFile {
write(string, WriteOptions) !
name string
@@ -32,7 +30,6 @@ pub fn (f File) typescript(path string, params WriteOptions) ! {
}
}
>>>>>>>> development:lib/core/code/model_file.v
pub struct VFile {
pub mut:

View File

@@ -2,22 +2,22 @@ module code
import freeflowuniverse.herolib.core.pathlib
pub interface IFolder {
pub interface IBasicFolder {
name string
files []IFile
modules []Module
write(string, WriteOptions) !
}
pub struct Folder {
pub struct BasicFolder {
pub:
name string
files []IFile
folders []IFolder
folders []IBasicFolder
modules []Module
}
pub fn (f Folder) write(path string, options WriteOptions) ! {
pub fn (f BasicFolder) write(path string, options WriteOptions) ! {
mut dir := pathlib.get_dir(
path: '${path}/${f.name}'
empty: options.overwrite

View File

@@ -1,85 +0,0 @@
module code
import freeflowuniverse.herolib.ui.console
import freeflowuniverse.herolib.core.pathlib
import os
import log
pub struct Module {
pub mut:
name string
description string
version string = '0.0.1'
license string = 'apache2'
vcs string = 'git'
files []IFile
folders []IFolder
modules []Module
in_src bool // whether mod will be generated in src folder
// model VFile
// methods VFile
}
pub fn new_module(mod Module) Module {
return Module {
...mod
files: mod.files.map(
if it is VFile {
IFile(VFile{...it, mod: mod.name})
} else {it}
)
}
}
pub fn (mod Module) write(path string, options WriteOptions) ! {
mut module_dir := pathlib.get_dir(
path: if mod.in_src { '${path}/src' } else { '${path}/${mod.name}' }
empty: options.overwrite
)!
console.print_debug("write ${module_dir.path}")
// pre:="v -n -w -enable-globals"
pre:="v -n -w -gc none -cc tcc -d use_openssl -enable-globals run"
if !options.overwrite && module_dir.exists() {
return
}
for file in mod.files {
console.print_debug("mod file write ${file.name}")
file.write(module_dir.path, options)!
}
for folder in mod.folders {
console.print_debug("mod folder write ${folder.name}")
folder.write('${path}/${mod.name}', options)!
}
for mod_ in mod.modules {
console.print_debug("mod write ${mod_.name}")
mod_.write('${path}/${mod.name}', options)!
}
if options.format {
console.print_debug("format ${module_dir.path}")
os.execute('v fmt -w ${module_dir.path}')
}
if options.compile {
console.print_debug("compile shared ${module_dir.path}")
os.execute_opt('${pre} -shared ${module_dir.path}') or {
log.fatal(err.msg())
}
}
if options.test {
console.print_debug("test ${module_dir.path}")
os.execute_opt('${pre} test ${module_dir.path}') or {
log.fatal(err.msg())
}
}
if options.document {
docs_path := '${path}/${mod.name}/docs'
console.print_debug("document ${module_dir.path}")
os.execute('v doc -f html -o ${docs_path} ${module_dir.path}')
}
mut mod_file := pathlib.get_file(path: '${module_dir.path}/v.mod')!
mod_file.write($tmpl('templates/v.mod.template'))!
}

View File

@@ -1,90 +0,0 @@
module code
import freeflowuniverse.herolib.core.texttools
pub struct Param {
pub mut:
required bool @[omitempty]
mutable bool @[omitempty]
is_shared bool @[omitempty]
is_optional bool @[omitempty]
is_result bool @[omitempty]
description string @[omitempty]
name string @[omitempty]
typ Type @[omitempty]
}
// // todo: maybe make 'is_' fields methods?
// pub struct Type {
// pub mut:
// is_reference bool @[str: skip]
// is_map bool @[str: skip]
// is_array bool
// is_mutable bool @[str: skip]
// is_shared bool @[str: skip]
// is_optional bool @[str: skip]
// is_result bool @[str: skip]
// symbol string
// mod string @[str: skip]
// }
@[params]
pub struct Params{
pub:
v string
}
pub fn new_param(params Params) !Param {
// TODO: implement function from file line
return parse_param(params.v)!
}
pub fn (param Param) vgen() string {
sym := param.typ.symbol()
param_name := texttools.snake_case(param.name)
mut vstr := '${param_name} ${sym}'
if param.mutable {
vstr = 'mut ${vstr}'
}
return '${vstr}'
}
pub fn (p Param) typescript() string {
name := texttools.camel_case(p.name)
suffix := if p.is_optional {'?'} else {''}
return '${name}${suffix}: ${p.typ.typescript()}'
}
pub fn parse_param(code_ string) !Param {
mut code := code_.trim_space()
if code == '!' {
return Param{is_result: true}
} else if code == '?' {
return Param{is_optional: true}
}
is_mut := code.starts_with('mut ')
if is_mut {
code = code.trim_string_left('mut ').trim_space()
}
split := code.split(' ').filter(it != '')
if split.len == 1 {
// means anonymous param
return Param{
typ: type_from_symbol(split[0])
mutable: is_mut
}
}
if split.len != 2 {
return error('invalid param format: ${code_}')
}
return Param{
name: split[0]
typ: type_from_symbol(split[1])
mutable: is_mut
}
}

View File

@@ -1,136 +0,0 @@
module code
import log
import os
import freeflowuniverse.herolib.core.texttools
pub struct Struct {
pub mut:
name string
description string
mod string
is_pub bool
embeds []Struct @[str: skip]
generics map[string]string @[str: skip]
attrs []Attribute
fields []StructField
}
// vgen_function generates a function statement for a function
pub fn (struct_ Struct) vgen() string {
name_ := if struct_.generics.len > 0 {
'${struct_.name}${vgen_generics(struct_.generics)}'
} else {
struct_.name
}
name := texttools.pascal_case(name_)
prefix := if struct_.is_pub {
'pub '
} else {
''
}
comments := if struct_.description.trim_space() != '' {
'// ${struct_.description.trim_space()}'
} else {''}
priv_fields := struct_.fields.filter(!it.is_mut && !it.is_pub).map(it.vgen())
pub_fields := struct_.fields.filter(!it.is_mut && it.is_pub).map(it.vgen())
mut_fields := struct_.fields.filter(it.is_mut && !it.is_pub).map(it.vgen())
pub_mut_fields := struct_.fields.filter(it.is_mut && it.is_pub).map(it.vgen())
mut struct_str := $tmpl('templates/struct/struct.v.template')
if false {
result := os.execute_opt('echo "${struct_str.replace('$', '\$')}" | v fmt') or {
log.debug(struct_str)
panic(err)
}
return result.output
}
return struct_str
}
pub struct Interface {
pub mut:
name string
description string
is_pub bool
embeds []Interface @[str: skip]
attrs []Attribute
fields []StructField
methods []Function
}
pub fn (iface Interface) vgen() string {
name := texttools.pascal_case(iface.name)
prefix := if iface.is_pub {
'pub'
} else {
''
}
mut fields := iface.fields.filter(!it.is_mut).map(it.vgen())
mut mut_fields := iface.fields.filter(it.is_mut).map(it.vgen())
fields << iface.methods.filter(!it.receiver.mutable).map(function_to_interface_field(it))
mut_fields << iface.methods.filter(it.receiver.mutable).map(function_to_interface_field(it))
mut iface_str := $tmpl('templates/interface/interface.v.template')
if false {
result := os.execute_opt('echo "${iface_str.replace('$', '\$')}" | v fmt') or {
log.debug(iface_str)
panic(err)
}
return result.output
}
return iface_str
}
pub fn function_to_interface_field(f Function) string {
param_types := f.params.map(it.typ.vgen()).join(', ')
return '${f.name}(${param_types}) ${f.result.typ.vgen()}'
}
pub struct StructField {
Param
pub mut:
comments []Comment
attrs []Attribute
description string
default string
is_pub bool
is_mut bool
is_ref bool
anon_struct Struct @[str: skip] // sometimes fields may hold anonymous structs
structure Struct @[str: skip]
}
pub fn (field StructField) vgen() string {
mut vstr := field.Param.vgen()
if field.description != '' {
vstr += '// ${field.description}'
}
return vstr
}
pub fn (structure Struct) get_type_symbol() string {
mut symbol := if structure.mod != '' {
'${structure.mod.all_after_last('.')}.${structure.name}'
} else {
structure.name
}
if structure.generics.len > 0 {
symbol = '${symbol}${vgen_generics(structure.generics)}'
}
return symbol
}
pub fn (s Struct) typescript() string {
name := texttools.name_fix_pascal(s.name)
fields := s.fields.map(it.typescript()).join_lines()
return 'export interface ${name} {\n${fields}\n}'
}

View File

@@ -1,158 +0,0 @@
module code
struct Float {
bytes int
}
// Integer types
pub const type_i8 = Integer{
bytes: 8
}
pub const type_u8 = Integer{
bytes: 8
signed: false
}
pub const type_i16 = Integer{
bytes: 16
}
pub const type_u16 = Integer{
bytes: 16
signed: false
}
pub const type_i32 = Integer{
bytes: 32
}
pub const type_u32 = Integer{
bytes: 32
signed: false
}
pub const type_i64 = Integer{
bytes: 64
}
pub const type_u64 = Integer{
bytes: 64
signed: false
}
// Floating-point types
pub const type_f32 = Float{
bytes: 32
}
pub const type_f64 = Float{
bytes: 64
}
pub type Type = Void | Map | Array | Object | Result | Integer | Alias | String | Boolean | Function
pub struct Boolean{}
pub struct Void{}
pub struct Integer {
bytes u8
signed bool = true
}
pub fn type_from_symbol(symbol_ string) Type {
mut symbol := symbol_.trim_space()
if symbol.starts_with('[]') {
return Array{type_from_symbol(symbol.all_after('[]'))}
} else if symbol == 'int' {
return Integer{}
} else if symbol == 'string' {
return String{}
} else if symbol == 'bool' || symbol == 'boolean' {
return Boolean{}
}
return Object{symbol}
}
pub fn (t Type) symbol() string {
return match t {
Array { '[]${t.typ.symbol()}' }
Object { t.name }
Result { '!${t.typ.symbol()}'}
Integer {
mut str := ''
if !t.signed {
str += 'u'
}
if t.bytes != 0 {
'${str}${t.bytes}'
} else {
'${str}int'
}
}
Alias {t.name}
String {'string'}
Boolean {'bool'}
Map{'map[string]${t.typ.symbol()}'}
Function{'fn ()'}
Void {''}
}
}
pub struct String {}
pub struct Array {
pub:
typ Type
}
pub struct Map {
pub:
typ Type
}
pub struct Object {
pub:
name string
}
pub struct Result {
pub:
typ Type
}
pub fn (t Type) typescript() string {
return match t {
Map {'Record<string, ${t.typ.typescript()}>'}
Array { '${t.typ.typescript()}[]' }
Object { t.name }
Result { '${t.typ.typescript()}'}
Boolean { 'boolean'}
Integer { 'number' }
Alias {t.name}
String {'string'}
Function {'func'}
Void {''}
}
}
// TODO: enfore that cant be both mutable and shared
pub fn (t Type) vgen() string {
return t.symbol()
}
pub fn (t Type) empty_value() string {
return match t {
Map {'{}'}
Array { '[]${t.typ.symbol()}{}' }
Object { if t.name != '' {'${t.name}{}'} else {''} }
Result { t.typ.empty_value() }
Boolean { 'false' }
Integer { '0' }
Alias {''}
String {"''"}
Function {''}
Void {''}
}
}

View File

@@ -1,134 +0,0 @@
module code
import freeflowuniverse.herolib.core.texttools
import freeflowuniverse.herolib.core.pathlib
import os
<<<<<<<< HEAD:lib/core/code/vfile.v
========
pub interface IFile {
write(string, WriteOptions) !
name string
}
pub struct File {
pub mut:
name string
extension string
content string
}
pub fn (f File) write(path string, params WriteOptions) ! {
mut fd_file := pathlib.get_file(path: '${path}/${f.name}.${f.extension}')!
fd_file.write(f.content)!
if f.extension == 'ts' {
return f.typescript(path, params)
}
}
pub fn (f File) typescript(path string, params WriteOptions) ! {
if params.format {
os.execute('npx prettier --write ${path}')
}
}
>>>>>>>> development:lib/core/code/model_file.v
pub struct VFile {
pub mut:
name string
mod string
imports []Import
consts []Const
items []CodeItem
content string
}
pub fn new_file(config VFile) VFile {
return VFile{
...config
mod: texttools.name_fix(config.mod)
items: config.items
}
}
pub fn (mut file VFile) add_import(import_ Import) ! {
for mut i in file.imports {
if i.mod == import_.mod {
i.add_types(import_.types)
return
}
}
file.imports << import_
}
pub fn (code VFile) write(path string, options WriteOptions) ! {
filename := '${options.prefix}${texttools.name_fix(code.name)}.v'
mut filepath := pathlib.get('${path}/${filename}')
if !options.overwrite && filepath.exists() {
return
}
imports_str := code.imports.map(it.vgen()).join_lines()
code_str := if code.content != '' {
code.content
} else {
vgen(code.items)
}
consts_str := if code.consts.len > 1 {
stmts := code.consts.map('${it.name} = ${it.value}')
'\nconst(\n${stmts.join('\n')}\n)\n'
} else if code.consts.len == 1 {
'\nconst ${code.consts[0].name} = ${code.consts[0].value}\n'
} else {
''
}
mut file := pathlib.get_file(
path: filepath.path
create: true
)!
mod_stmt := if code.mod == '' {''} else {
'module ${code.mod}'
}
file.write('${mod_stmt}\n${imports_str}\n${consts_str}${code_str}')!
if options.format {
os.execute('v fmt -w ${file.path}')
}
}
pub fn (file VFile) get_function(name string) ?Function {
functions := file.items.filter(it is Function).map(it as Function)
target_lst := functions.filter(it.name == name)
if target_lst.len == 0 {
return none
}
if target_lst.len > 1 {
panic('This should never happen')
}
return target_lst[0]
}
pub fn (mut file VFile) set_function(function Function) ! {
function_names := file.items.map(if it is Function { it.name } else { '' })
index := function_names.index(function.name)
if index == -1 {
return error('function not found')
}
file.items[index] = function
}
pub fn (file VFile) functions() []Function {
return file.items.filter(it is Function).map(it as Function)
}
pub fn (file VFile) structs() []Struct {
return file.items.filter(it is Struct).map(it as Struct)
}

View File

@@ -1,73 +0,0 @@
module code
import os
import log
import freeflowuniverse.herolib.core.texttools
pub struct WriteCode {
destination string
}
interface ICodeItem {
vgen() string
}
pub fn vgen(code []CodeItem) string {
mut str := ''
for item in code {
if item is Function {
str += '\n${item.vgen()}'
}
if item is Struct {
str += '\n${item.vgen()}'
}
if item is Interface {
str += '\n${item.vgen()}'
}
if item is CustomCode {
str += '\n${item.vgen()}'
}
}
return str
}
// pub fn (code Code) vgen() string {
// return code.items.map(it.vgen()).join_lines()
// }
// vgen_import generates an import statement for a given type
pub fn (import_ Import) vgen() string {
types_str := if import_.types.len > 0 {
'{${import_.types.join(', ')}}'
} else {
''
} // comma separated string list of types
return 'import ${import_.mod} ${types_str}'
}
pub fn vgen_generics(generics map[string]string) string {
if generics.keys().len == 0 {
return ''
}
mut vstr := '['
for key, val in generics {
vstr += if val != '' { val } else { key }
}
return '${vstr}]'
}
pub fn (custom CustomCode) vgen() string {
return custom.text
}
@[params]
pub struct WriteOptions {
pub:
format bool
overwrite bool
document bool
prefix string
compile bool // whether to compile the written code
test bool // whether to test the written code
}

View File

@@ -87,7 +87,7 @@ module codegen
// description: function.result.description
// }
// pascal_name := texttools.snake_case_to_pascal(function.name)
// pascal_name := texttools.pascal_case(function.name)
// function_name := if function.mod != '' {
// '${function.mod}.${pascal_name}'
// } else {

View File

@@ -35,7 +35,7 @@ pub fn generate_handler_file(o OpenRPC, receiver Struct, method_map map[string]F
pub fn generate_handler_test_file(o OpenRPC, receiver Struct, method_map map[string]Function, object_map map[string]Struct) !VFile {
name := texttools.name_fix(o.info.title)
handler_name := texttools.name_fix_pascal_to_snake(receiver.name)
handler_name := texttools.snake_case(receiver.name)
consts := CustomCode{"const actor_name = '${handler_name}_test_actor'"}
clean_code := 'mut actor := get(name: actor_name)!\nactor.backend.reset()!'

View File

@@ -14,7 +14,7 @@ pub fn generate_model(o OpenRPC) ![]CodeItem {
if schema_ is Schema {
mut schema := schema_
if schema.title == '' {
schema.title = texttools.snake_case_to_pascal(key)
schema.title = texttools.pascal_case(key)
}
structs << schema_to_code(schema)
}

View File

@@ -86,7 +86,7 @@ module codegen
// // description: function.result.description
// // }
// pascal_name := texttools.snake_case_to_pascal(function.name)
// pascal_name := texttools.pascal_case(function.name)
// function_name := if function.mod != '' {
// '${pascal_name}'
// } else {

View File

@@ -21,7 +21,7 @@ pub fn method_to_function(method Method) !Function {
}
return Function{
name: texttools.name_fix_pascal_to_snake(method.name)
name: texttools.snake_case(method.name)
params: params
result: result
}