166 lines
5.2 KiB
V
166 lines
5.2 KiB
V
module generator
|
|
|
|
import incubaid.herolib.develop.codetools as code { CodeItem, Function, Import, Param, Result, Struct, VFile }
|
|
import incubaid.herolib.core.texttools
|
|
import incubaid.herolib.schemas.openapi
|
|
import incubaid.herolib.schemas.openrpc
|
|
import incubaid.herolib.schemas.openrpc.codegen { content_descriptor_to_parameter, content_descriptor_to_struct }
|
|
import incubaid.herolib.schemas.jsonschema { Schema }
|
|
import incubaid.herolib.schemas.jsonschema.codegen as jsonschema_codegen
|
|
import incubaid.herolib.baobab.specification { ActorMethod, ActorSpecification }
|
|
import log
|
|
|
|
const crud_prefixes = ['new', 'get', 'set', 'delete', 'list']
|
|
|
|
pub struct Source {
|
|
openapi_path ?string
|
|
openrpc_path ?string
|
|
}
|
|
|
|
pub fn generate_methods_file_str(source Source) !string {
|
|
actor_spec := if path := source.openapi_path {
|
|
specification.from_openapi(openapi.new(path: path)!)!
|
|
} else if path := source.openrpc_path {
|
|
specification.from_openrpc(openrpc.new(path: path)!)!
|
|
} else {
|
|
panic('No openapi or openrpc path provided')
|
|
}
|
|
return generate_methods_file(actor_spec)!.write_str()!
|
|
}
|
|
|
|
pub fn generate_methods_file(spec ActorSpecification) !VFile {
|
|
name_snake := texttools.snake_case(spec.name)
|
|
actor_name_pascal := texttools.pascal_case(spec.name)
|
|
|
|
receiver := generate_methods_receiver(spec.name)
|
|
receiver_param := Param{
|
|
mutable: true
|
|
name: name_snake[0].ascii_str() // receiver is first letter of domain
|
|
typ: Result{code.Object{receiver.name}}
|
|
}
|
|
|
|
mut items := [CodeItem(receiver), CodeItem(generate_core_factory(receiver_param))]
|
|
for method in spec.methods {
|
|
items << generate_method_code(receiver_param, ActorMethod{
|
|
...method
|
|
category: spec.method_type(method)
|
|
})!
|
|
}
|
|
|
|
return VFile{
|
|
name: 'methods'
|
|
imports: [
|
|
Import{
|
|
mod: 'incubaid.herolib.baobab.osis'
|
|
types: ['OSIS']
|
|
},
|
|
]
|
|
items: items
|
|
}
|
|
}
|
|
|
|
fn generate_methods_receiver(name string) Struct {
|
|
return Struct{
|
|
is_pub: true
|
|
name: '${texttools.pascal_case(name)}'
|
|
fields: [
|
|
code.StructField{
|
|
is_mut: true
|
|
name: 'osis'
|
|
typ: code.Object{'OSIS'}
|
|
},
|
|
]
|
|
}
|
|
}
|
|
|
|
fn generate_core_factory(receiver Param) Function {
|
|
return Function{
|
|
is_pub: true
|
|
name: 'new_${receiver.typ.symbol()}'
|
|
body: 'return ${receiver.typ.symbol().trim_left('!?')}{osis: osis.new()!}'
|
|
result: receiver
|
|
}
|
|
}
|
|
|
|
// returns bodyless method prototype
|
|
pub fn generate_method_code(receiver Param, method ActorMethod) ![]CodeItem {
|
|
result_param := content_descriptor_to_parameter(method.result)!
|
|
|
|
mut method_code := []CodeItem{}
|
|
// TODO: document assumption
|
|
obj_params := method.parameters.filter(if it.schema is Schema {
|
|
it.schema.typ == 'object'
|
|
} else {
|
|
false
|
|
}).map(content_descriptor_to_struct(it))
|
|
if obj_param := obj_params[0] {
|
|
method_code << obj_param
|
|
}
|
|
|
|
// check if method is a Base Object CRUD Method and
|
|
// if so generate the method's body
|
|
// TODO: smart generation of method body using AI
|
|
// body := match method.category {
|
|
// .base_object_new { base_object_new_body(receiver, method)! }
|
|
// .base_object_get { base_object_get_body(receiver, method)! }
|
|
// .base_object_set { base_object_set_body(receiver, method)! }
|
|
// .base_object_delete { base_object_delete_body(receiver, method)! }
|
|
// .base_object_list { base_object_list_body(receiver, method)! }
|
|
// else { "panic('implement')" }
|
|
// }
|
|
|
|
body := "panic('implement')"
|
|
|
|
fn_prototype := generate_method_prototype(receiver, method)!
|
|
method_code << Function{
|
|
...fn_prototype
|
|
body: body
|
|
}
|
|
return method_code
|
|
}
|
|
|
|
// returns bodyless method prototype
|
|
pub fn generate_method_prototype(receiver Param, method ActorMethod) !Function {
|
|
result_param := content_descriptor_to_parameter(method.result)!
|
|
return Function{
|
|
name: texttools.snake_case(method.name)
|
|
receiver: receiver
|
|
result: Param{
|
|
...result_param
|
|
typ: Result{result_param.typ}
|
|
}
|
|
summary: method.summary
|
|
description: method.description
|
|
params: method.parameters.map(content_descriptor_to_parameter(it)!)
|
|
}
|
|
}
|
|
|
|
fn base_object_new_body(receiver Param, method ActorMethod) !string {
|
|
parameter := content_descriptor_to_parameter(method.parameters[0])!
|
|
return 'return ${receiver.name}.osis.new[${parameter.typ.vgen()}](${texttools.snake_case(parameter.name)})!'
|
|
}
|
|
|
|
fn base_object_get_body(receiver Param, method ActorMethod) !string {
|
|
parameter := content_descriptor_to_parameter(method.parameters[0])!
|
|
result := content_descriptor_to_parameter(method.result)!
|
|
return 'return ${receiver.name}.osis.get[${result.typ.vgen()}](${texttools.snake_case(parameter.name)})!'
|
|
}
|
|
|
|
fn base_object_set_body(receiver Param, method ActorMethod) !string {
|
|
parameter := content_descriptor_to_parameter(method.parameters[0])!
|
|
return 'return ${receiver.name}.osis.set[${parameter.typ.vgen()}](${parameter.name})!'
|
|
}
|
|
|
|
fn base_object_delete_body(receiver Param, method ActorMethod) !string {
|
|
parameter := content_descriptor_to_parameter(method.parameters[0])!
|
|
return '${receiver.name}.osis.delete(${texttools.snake_case(parameter.name)})!'
|
|
}
|
|
|
|
fn base_object_list_body(receiver Param, method ActorMethod) !string {
|
|
// result := content_descriptor_to_parameter(method.result)!
|
|
// log.error('result typ: ${result.typ}')
|
|
// base_object_type := (result.typ as Array).typ
|
|
// return 'return ${receiver.name}.osis.list[${base_object_type.symbol()}]()!'
|
|
return 'return'
|
|
}
|