typescript client generation wip
This commit is contained in:
130
lib/baobab/generator/client_typescript.v
Normal file
130
lib/baobab/generator/client_typescript.v
Normal file
@@ -0,0 +1,130 @@
|
||||
module generator
|
||||
|
||||
import freeflowuniverse.herolib.core.code {Folder, File}
|
||||
import freeflowuniverse.herolib.core.texttools
|
||||
import freeflowuniverse.herolib.schemas.jsonschema.codegen { schema_to_struct }
|
||||
import freeflowuniverse.herolib.schemas.openrpc.codegen as openrpc_codegen { content_descriptor_to_parameter }
|
||||
import freeflowuniverse.herolib.baobab.specification {ActorSpecification, ActorMethod, BaseObject}
|
||||
|
||||
pub fn typescript_client_folder(spec ActorSpecification) code.Folder {
|
||||
return Folder {
|
||||
name: 'client_typescript'
|
||||
files: [
|
||||
ts_client_model_file(spec.objects),
|
||||
ts_client_methods_file(spec)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
// generates a model.ts file for given base objects
|
||||
fn ts_client_model_file(objs []BaseObject) File {
|
||||
return File {
|
||||
name: 'model'
|
||||
extension: 'ts'
|
||||
content: objs.map(schema_to_struct(it.schema) or {panic(err)})
|
||||
.map(it.typescript())
|
||||
.join_lines()
|
||||
}
|
||||
}
|
||||
|
||||
// generates a methods.ts file for given actor methods
|
||||
pub fn ts_client_methods_file(spec_ ActorSpecification) File {
|
||||
spec := spec_.validate()
|
||||
mut files := []File{}
|
||||
mut methods := []string{}
|
||||
|
||||
// for each base object generate ts client methods
|
||||
// for the objects existing CRUD+LF methods
|
||||
for obj in spec.objects {
|
||||
if m := obj.new_method {
|
||||
methods << ts_client_new_fn(obj.name())
|
||||
}
|
||||
if m := obj.get_method {
|
||||
methods << ts_client_get_fn(obj.name())
|
||||
}
|
||||
if m := obj.set_method {
|
||||
methods << ts_client_set_fn(obj.name())
|
||||
}
|
||||
if m := obj.delete_method {
|
||||
methods << ts_client_delete_fn(obj.name())
|
||||
}
|
||||
if m := obj.list_method {
|
||||
methods << ts_client_list_fn(obj.name())
|
||||
}
|
||||
methods << obj.other_methods.map(ts_client_fn_prototype(it))
|
||||
}
|
||||
|
||||
return File {
|
||||
name: 'methods'
|
||||
extension: 'ts'
|
||||
content: methods.join_lines()
|
||||
}
|
||||
}
|
||||
|
||||
@[params]
|
||||
pub struct TSClientFunctionParams {
|
||||
endpoint string // prefix for the Rest API endpoint
|
||||
}
|
||||
|
||||
fn get_endpoint_root(root string) string {
|
||||
return if root == '' {
|
||||
''
|
||||
} else {
|
||||
"/${root.trim('/')}"
|
||||
}
|
||||
}
|
||||
|
||||
// generates a Base Object's `create` method
|
||||
pub fn ts_client_new_fn(object string, params TSClientFunctionParams) string {
|
||||
name_snake := texttools.name_fix_snake(object)
|
||||
name_pascal := texttools.name_fix_pascal(object)
|
||||
root := get_endpoint_root(params.endpoint)
|
||||
|
||||
return "async create${name_snake}(object: Omit<${name_pascal}, 'id'>): Promise<${name_pascal}> {
|
||||
return this.restClient.post<${name_pascal}>('${root}/${name_snake}', board);
|
||||
}"
|
||||
}
|
||||
|
||||
pub fn ts_client_get_fn(object string, params TSClientFunctionParams) string {
|
||||
name_snake := texttools.name_fix_snake(object)
|
||||
name_pascal := texttools.name_fix_pascal(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 }"
|
||||
}
|
||||
|
||||
pub fn ts_client_set_fn(object string, params TSClientFunctionParams) string {
|
||||
name_snake := texttools.name_fix_snake(object)
|
||||
name_pascal := texttools.name_fix_pascal(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 }"
|
||||
}
|
||||
|
||||
pub fn ts_client_delete_fn(object string, params TSClientFunctionParams) string {
|
||||
name_snake := texttools.name_fix_snake(object)
|
||||
name_pascal := texttools.name_fix_pascal(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 }"
|
||||
}
|
||||
|
||||
pub fn ts_client_list_fn(object string, params TSClientFunctionParams) string {
|
||||
name_snake := texttools.name_fix_snake(object)
|
||||
name_pascal := texttools.name_fix_pascal(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 }"
|
||||
}
|
||||
|
||||
// generates a function prototype given an `ActorMethod`
|
||||
pub fn ts_client_fn_prototype(method ActorMethod) string {
|
||||
name := texttools.name_fix_pascal(method.name)
|
||||
params := method.parameters
|
||||
.map(content_descriptor_to_parameter(it) or {panic(err)})
|
||||
.map(it.typescript())
|
||||
.join(', ')
|
||||
|
||||
return_type := content_descriptor_to_parameter(method.result) or {panic(err)}.typ.typescript()
|
||||
return 'async ${name}(${params}): Promise<${return_type}> {}'
|
||||
}
|
||||
202
lib/baobab/generator/client_typescript_test.v
Normal file
202
lib/baobab/generator/client_typescript_test.v
Normal file
@@ -0,0 +1,202 @@
|
||||
module generator
|
||||
|
||||
import x.json2 as json
|
||||
import arrays
|
||||
import freeflowuniverse.herolib.core.code
|
||||
import freeflowuniverse.herolib.baobab.specification
|
||||
import freeflowuniverse.herolib.schemas.openrpc
|
||||
import freeflowuniverse.herolib.schemas.jsonschema
|
||||
|
||||
const specification = specification.ActorSpecification{
|
||||
name: 'Pet Store'
|
||||
description: 'A sample API for a pet store'
|
||||
structure: code.Struct{}
|
||||
interfaces: [.openapi]
|
||||
methods: [
|
||||
specification.ActorMethod{
|
||||
name: 'listPets'
|
||||
summary: 'List all pets'
|
||||
example: openrpc.ExamplePairing{
|
||||
params: [
|
||||
openrpc.ExampleRef(openrpc.Example{
|
||||
name: 'Example limit'
|
||||
description: 'Example Maximum number of pets to return'
|
||||
value: 10
|
||||
})
|
||||
]
|
||||
result: openrpc.ExampleRef(openrpc.Example{
|
||||
name: 'Example response'
|
||||
value: json.raw_decode('[
|
||||
{"id": 1, "name": "Fluffy", "tag": "dog"},
|
||||
{"id": 2, "name": "Whiskers", "tag": "cat"}
|
||||
]')!
|
||||
})
|
||||
}
|
||||
parameters: [
|
||||
openrpc.ContentDescriptor{
|
||||
name: 'limit'
|
||||
summary: 'Maximum number of pets to return'
|
||||
description: 'Maximum number of pets to return'
|
||||
required: false
|
||||
schema: jsonschema.SchemaRef(jsonschema.Schema{
|
||||
...jsonschema.schema_u32,
|
||||
example: 10
|
||||
})
|
||||
}
|
||||
]
|
||||
result: openrpc.ContentDescriptor{
|
||||
name: 'pets'
|
||||
description: 'A paged array of pets'
|
||||
schema: jsonschema.SchemaRef(jsonschema.Schema{
|
||||
typ: 'array'
|
||||
items: jsonschema.Items(jsonschema.SchemaRef(jsonschema.Schema{
|
||||
id: 'pet'
|
||||
title: 'Pet'
|
||||
typ: 'object'
|
||||
properties: {
|
||||
'id': jsonschema.SchemaRef(jsonschema.Reference{
|
||||
ref: '#/components/schemas/PetId'
|
||||
}),
|
||||
'name': jsonschema.SchemaRef(jsonschema.Schema{
|
||||
typ: 'string'
|
||||
}),
|
||||
'tag': jsonschema.SchemaRef(jsonschema.Schema{
|
||||
typ: 'string'
|
||||
})
|
||||
}
|
||||
required: ['id', 'name']
|
||||
}))
|
||||
})
|
||||
}
|
||||
errors: [
|
||||
openrpc.ErrorSpec{
|
||||
code: 400
|
||||
message: 'Invalid request'
|
||||
}
|
||||
]
|
||||
},
|
||||
specification.ActorMethod{
|
||||
name: 'createPet'
|
||||
summary: 'Create a new pet'
|
||||
example: openrpc.ExamplePairing{
|
||||
result: openrpc.ExampleRef(openrpc.Example{
|
||||
name: 'Example response'
|
||||
value: '[]'
|
||||
})
|
||||
}
|
||||
result: openrpc.ContentDescriptor{
|
||||
name: 'result'
|
||||
description: 'The response of the operation.'
|
||||
required: true
|
||||
}
|
||||
errors: [
|
||||
openrpc.ErrorSpec{
|
||||
code: 400
|
||||
message: 'Invalid input'
|
||||
}
|
||||
]
|
||||
},
|
||||
specification.ActorMethod{
|
||||
name: 'getPet'
|
||||
summary: 'Get a pet by ID'
|
||||
example: openrpc.ExamplePairing{
|
||||
params: [
|
||||
openrpc.ExampleRef(openrpc.Example{
|
||||
name: 'Example petId'
|
||||
description: 'Example ID of the pet to retrieve'
|
||||
value: 1
|
||||
})
|
||||
]
|
||||
result: openrpc.ExampleRef(openrpc.Example{
|
||||
name: 'Example response'
|
||||
value: json.raw_decode('{"id": 1, "name": "Fluffy", "tag": "dog"}')!
|
||||
})
|
||||
}
|
||||
parameters: [
|
||||
openrpc.ContentDescriptor{
|
||||
name: 'petId'
|
||||
summary: 'ID of the pet to retrieve'
|
||||
description: 'ID of the pet to retrieve'
|
||||
required: true
|
||||
schema: jsonschema.SchemaRef(jsonschema.Schema{
|
||||
...jsonschema.schema_u32,
|
||||
format:'uint32'
|
||||
example: 1
|
||||
})
|
||||
}
|
||||
]
|
||||
result: openrpc.ContentDescriptor{
|
||||
name: 'result'
|
||||
description: 'The response of the operation.'
|
||||
required: true
|
||||
schema: jsonschema.SchemaRef(jsonschema.Reference{
|
||||
ref: '#/components/schemas/Pet'
|
||||
})
|
||||
}
|
||||
errors: [
|
||||
openrpc.ErrorSpec{
|
||||
code: 404
|
||||
message: 'Pet not found'
|
||||
}
|
||||
]
|
||||
},
|
||||
specification.ActorMethod{
|
||||
name: 'deletePet'
|
||||
summary: 'Delete a pet by ID'
|
||||
example: openrpc.ExamplePairing{
|
||||
params: [
|
||||
openrpc.ExampleRef(openrpc.Example{
|
||||
name: 'Example petId'
|
||||
description: 'Example ID of the pet to delete'
|
||||
value: 1
|
||||
})
|
||||
]
|
||||
}
|
||||
parameters: [
|
||||
openrpc.ContentDescriptor{
|
||||
name: 'petId'
|
||||
summary: 'ID of the pet to delete'
|
||||
description: 'ID of the pet to delete'
|
||||
required: true
|
||||
schema: jsonschema.SchemaRef(jsonschema.Schema{
|
||||
...jsonschema.schema_u32,
|
||||
example: 1
|
||||
})
|
||||
}
|
||||
]
|
||||
result: openrpc.ContentDescriptor{
|
||||
name: 'result'
|
||||
description: 'The response of the operation.'
|
||||
required: true
|
||||
}
|
||||
errors: [
|
||||
openrpc.ErrorSpec{
|
||||
code: 404
|
||||
message: 'Pet not found'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
objects: [
|
||||
specification.BaseObject{
|
||||
schema: jsonschema.Schema{
|
||||
title: 'Pet'
|
||||
typ: 'object'
|
||||
properties: {
|
||||
'id': jsonschema.schema_u32,
|
||||
'name': jsonschema.SchemaRef(jsonschema.Schema{
|
||||
typ: 'string'
|
||||
}),
|
||||
'tag': jsonschema.SchemaRef(jsonschema.Schema{
|
||||
typ: 'string'
|
||||
})
|
||||
}
|
||||
required: ['id', 'name']
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
fn test_typescript_client_folder() {
|
||||
client := typescript_client_folder(specification)
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
module generator
|
||||
|
||||
import freeflowuniverse.herolib.core.code { Folder, IFile, VFile, CodeItem, File, Function, Import, Module, Struct, CustomCode }
|
||||
import freeflowuniverse.herolib.core.code { Folder, IFolder, IFile, VFile, CodeItem, File, Function, Import, Module, Struct, CustomCode }
|
||||
import freeflowuniverse.herolib.core.texttools
|
||||
import freeflowuniverse.herolib.baobab.specification {ActorMethod, ActorSpecification, ActorInterface}
|
||||
import json
|
||||
@@ -13,6 +13,7 @@ pub:
|
||||
|
||||
pub fn generate_actor_module(spec ActorSpecification, params Params) !Module {
|
||||
mut files := []IFile{}
|
||||
mut folders := []IFolder{}
|
||||
|
||||
files = [
|
||||
generate_readme_file(spec)!,
|
||||
@@ -56,9 +57,9 @@ pub fn generate_actor_module(spec ActorSpecification, params Params) !Module {
|
||||
files << iface_file
|
||||
files << iface_test_file
|
||||
|
||||
// add openrpc.json to docs
|
||||
// TODO
|
||||
// add openapi.json to docs
|
||||
docs_files << generate_openapi_file(openapi_spec)!
|
||||
folders << typescript_client_folder(spec)
|
||||
}
|
||||
.http {
|
||||
// interfaces that have http controllers
|
||||
@@ -79,20 +80,18 @@ pub fn generate_actor_module(spec ActorSpecification, params Params) !Module {
|
||||
|
||||
|
||||
// folder with docs
|
||||
docs_folder := Folder {
|
||||
folders << Folder {
|
||||
name: 'docs'
|
||||
files: docs_files
|
||||
}
|
||||
folders << generate_scripts_folder()
|
||||
|
||||
// create module with code files and docs folder
|
||||
name_fixed := texttools.name_fix_snake(spec.name)
|
||||
return code.new_module(
|
||||
name: '${name_fixed}_actor'
|
||||
files: files
|
||||
folders: [
|
||||
docs_folder,
|
||||
generate_scripts_folder()
|
||||
]
|
||||
folders: folders
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -76,8 +76,32 @@ const actor_spec = specification.ActorSpecification{
|
||||
]
|
||||
},
|
||||
specification.ActorMethod{
|
||||
name: 'createPet'
|
||||
name: 'newPet'
|
||||
summary: 'Create a new pet'
|
||||
parameters: [
|
||||
openrpc.ContentDescriptor{
|
||||
name: 'result'
|
||||
description: 'The response of the operation.'
|
||||
required: true
|
||||
schema: jsonschema.SchemaRef(jsonschema.Schema{
|
||||
id: 'pet'
|
||||
title: 'Pet'
|
||||
typ: 'object'
|
||||
properties: {
|
||||
'id': jsonschema.SchemaRef(jsonschema.Reference{
|
||||
ref: '#/components/schemas/PetId'
|
||||
}),
|
||||
'name': jsonschema.SchemaRef(jsonschema.Schema{
|
||||
typ: 'string'
|
||||
}),
|
||||
'tag': jsonschema.SchemaRef(jsonschema.Schema{
|
||||
typ: 'string'
|
||||
})
|
||||
}
|
||||
required: ['id', 'name']
|
||||
})
|
||||
}
|
||||
]
|
||||
example: openrpc.ExamplePairing{
|
||||
result: openrpc.ExampleRef(openrpc.Example{
|
||||
name: 'Example response'
|
||||
@@ -85,9 +109,14 @@ const actor_spec = specification.ActorSpecification{
|
||||
})
|
||||
}
|
||||
result: openrpc.ContentDescriptor{
|
||||
name: 'result'
|
||||
description: 'The response of the operation.'
|
||||
name: 'petId'
|
||||
summary: 'ID of the created pet'
|
||||
description: 'ID of the created pet'
|
||||
required: true
|
||||
schema: jsonschema.SchemaRef(jsonschema.Schema{
|
||||
...jsonschema.schema_u32,
|
||||
example: 1
|
||||
})
|
||||
}
|
||||
errors: [
|
||||
openrpc.ErrorSpec{
|
||||
|
||||
@@ -16,19 +16,13 @@ pub fn generate_methods_file(spec ActorSpecification) !VFile {
|
||||
method_fn := generate_method_function(spec.name, method)!
|
||||
// check if method is a Base Object CRUD Method and
|
||||
// if so generate the method's body
|
||||
body := if is_base_object_new_method(method) {
|
||||
generate_base_object_new_body(method)!
|
||||
} else if is_base_object_get_method(method) {
|
||||
generate_base_object_get_body(method)!
|
||||
} else if is_base_object_set_method(method) {
|
||||
generate_base_object_set_body(method)!
|
||||
} else if is_base_object_delete_method(method) {
|
||||
generate_base_object_delete_body(method)!
|
||||
} else if is_base_object_list_method(method) {
|
||||
generate_base_object_list_body(method)!
|
||||
} else {
|
||||
// default actor method body
|
||||
"panic('implement')"
|
||||
body := match spec.method_type(method) {
|
||||
.base_object_new { base_object_new_body(method)! }
|
||||
.base_object_get { base_object_get_body(method)! }
|
||||
.base_object_set { base_object_set_body(method)! }
|
||||
.base_object_delete { base_object_delete_body(method)! }
|
||||
.base_object_list { base_object_list_body(method)! }
|
||||
else {"panic('implement')"}
|
||||
}
|
||||
items << Function{...method_fn, body: body}
|
||||
}
|
||||
@@ -53,50 +47,29 @@ pub fn generate_method_function(actor_name string, method ActorMethod) !Function
|
||||
}
|
||||
}
|
||||
|
||||
fn is_base_object_new_method(method ActorMethod) bool {
|
||||
return method.name.starts_with('new')
|
||||
}
|
||||
|
||||
fn is_base_object_get_method(method ActorMethod) bool {
|
||||
return method.name.starts_with('get')
|
||||
}
|
||||
|
||||
fn is_base_object_set_method(method ActorMethod) bool {
|
||||
return method.name.starts_with('set')
|
||||
}
|
||||
|
||||
fn is_base_object_delete_method(method ActorMethod) bool {
|
||||
return method.name.starts_with('delete')
|
||||
}
|
||||
|
||||
fn is_base_object_list_method(method ActorMethod) bool {
|
||||
return method.name.starts_with('list')
|
||||
}
|
||||
|
||||
fn generate_base_object_new_body(method ActorMethod) !string {
|
||||
fn base_object_new_body(method ActorMethod) !string {
|
||||
parameter := content_descriptor_to_parameter(method.parameters[0])!
|
||||
return 'return actor.osis.new[${parameter.typ.vgen()}](${texttools.name_fix_snake(parameter.name)})!'
|
||||
}
|
||||
|
||||
fn generate_base_object_get_body(method ActorMethod) !string {
|
||||
fn base_object_get_body(method ActorMethod) !string {
|
||||
parameter := content_descriptor_to_parameter(method.parameters[0])!
|
||||
result := content_descriptor_to_parameter(method.result)!
|
||||
return 'return actor.osis.get[${result.typ.vgen()}](${texttools.name_fix_snake(parameter.name)})!'
|
||||
}
|
||||
|
||||
fn generate_base_object_set_body(method ActorMethod) !string {
|
||||
fn base_object_set_body(method ActorMethod) !string {
|
||||
parameter := content_descriptor_to_parameter(method.parameters[0])!
|
||||
return 'return actor.osis.set[${parameter.typ.vgen()}](${parameter.name})!'
|
||||
}
|
||||
|
||||
fn generate_base_object_delete_body(method ActorMethod) !string {
|
||||
fn base_object_delete_body(method ActorMethod) !string {
|
||||
parameter := content_descriptor_to_parameter(method.parameters[0])!
|
||||
return 'actor.osis.delete(${texttools.name_fix_snake(parameter.name)})!'
|
||||
}
|
||||
|
||||
fn generate_base_object_list_body(method ActorMethod) !string {
|
||||
fn base_object_list_body(method ActorMethod) !string {
|
||||
result := content_descriptor_to_parameter(method.result)!
|
||||
|
||||
base_object_type := (result.typ as Array).typ
|
||||
return 'return actor.osis.list[${base_object_type.symbol()}]()!'
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ pub fn from_openapi(spec OpenAPI) !ActorSpecification {
|
||||
|
||||
// Extract objects from OpenAPI components.schemas
|
||||
for name, schema in spec.components.schemas {
|
||||
objects << BaseObject{schema as Schema}
|
||||
objects << BaseObject{schema: schema as Schema}
|
||||
}
|
||||
|
||||
return ActorSpecification{
|
||||
|
||||
@@ -2,7 +2,7 @@ module specification
|
||||
|
||||
import freeflowuniverse.herolib.core.code { Struct, Function }
|
||||
import freeflowuniverse.herolib.schemas.openrpc {ExamplePairing, ContentDescriptor, ErrorSpec}
|
||||
import freeflowuniverse.herolib.schemas.jsonschema {Schema}
|
||||
import freeflowuniverse.herolib.schemas.jsonschema {Schema, Reference}
|
||||
|
||||
pub struct ActorSpecification {
|
||||
pub mut:
|
||||
@@ -34,6 +34,164 @@ pub:
|
||||
}
|
||||
|
||||
pub struct BaseObject {
|
||||
pub:
|
||||
pub mut:
|
||||
schema Schema
|
||||
new_method ?ActorMethod
|
||||
get_method ?ActorMethod
|
||||
set_method ?ActorMethod
|
||||
delete_method ?ActorMethod
|
||||
list_method ?ActorMethod
|
||||
filter_method ?ActorMethod
|
||||
other_methods []ActorMethod
|
||||
}
|
||||
|
||||
pub enum MethodCategory {
|
||||
base_object_new
|
||||
base_object_get
|
||||
base_object_set
|
||||
base_object_delete
|
||||
base_object_list
|
||||
other
|
||||
}
|
||||
|
||||
// returns whether method belongs to a given base object
|
||||
// TODO: link to more info about base object methods
|
||||
fn (m ActorMethod) belongs_to_object(obj BaseObject) bool {
|
||||
base_obj_is_param := m.parameters
|
||||
.filter(it.schema is Schema)
|
||||
.map(it.schema as Schema)
|
||||
.any(it.id == obj.schema.id)
|
||||
|
||||
base_obj_is_result := if m.result.schema is Schema {
|
||||
m.result.schema.id == obj.schema.id
|
||||
} else {
|
||||
ref := m.result.schema as Reference
|
||||
ref.ref.all_after_last('/') == obj.name()
|
||||
}
|
||||
|
||||
return base_obj_is_param || base_obj_is_result
|
||||
}
|
||||
|
||||
pub fn (s ActorSpecification) validate() ActorSpecification {
|
||||
mut validated_objects := []BaseObject{}
|
||||
for obj_ in s.objects {
|
||||
mut obj := obj_
|
||||
if obj.schema.id == '' {
|
||||
obj.schema.id = obj.schema.title
|
||||
}
|
||||
methods := s.methods.filter(it.belongs_to_object(obj))
|
||||
|
||||
if m := methods.filter(it.is_new_method())[0] {
|
||||
obj.new_method = m
|
||||
}
|
||||
if m := methods.filter(it.is_set_method())[0] {
|
||||
obj.set_method = m
|
||||
}
|
||||
if m := methods.filter(it.is_get_method())[0] {
|
||||
obj.get_method = m
|
||||
}
|
||||
if m := methods.filter(it.is_delete_method())[0] {
|
||||
obj.delete_method = m
|
||||
}
|
||||
if m := methods.filter(it.is_list_method())[0] {
|
||||
obj.list_method = m
|
||||
}
|
||||
validated_objects << BaseObject {
|
||||
...obj
|
||||
other_methods: methods.filter(!it.is_crudlf_method())
|
||||
}
|
||||
}
|
||||
return ActorSpecification {
|
||||
...s,
|
||||
objects: validated_objects
|
||||
}
|
||||
}
|
||||
|
||||
// method category returns what category a method falls under
|
||||
pub fn (s ActorSpecification) method_type(method ActorMethod) MethodCategory {
|
||||
return if s.is_base_object_new_method(method) {
|
||||
.base_object_new
|
||||
} else if s.is_base_object_get_method(method) {
|
||||
.base_object_get
|
||||
} else if s.is_base_object_set_method(method) {
|
||||
.base_object_set
|
||||
} else if s.is_base_object_delete_method(method) {
|
||||
.base_object_delete
|
||||
} else if s.is_base_object_list_method(method) {
|
||||
.base_object_list
|
||||
} else {
|
||||
.other
|
||||
}
|
||||
}
|
||||
|
||||
// a base object method is a method that is a
|
||||
// CRUD+list+filter method of a base object
|
||||
fn (s ActorSpecification) is_base_object_method(method ActorMethod) bool {
|
||||
base_obj_is_param := method.parameters
|
||||
.filter(it.schema is Schema)
|
||||
.map(it.schema as Schema)
|
||||
.any(it.id in s.objects.map(it.schema.id))
|
||||
|
||||
base_obj_is_result := if method.result.schema is Schema {
|
||||
method.result.schema.id in s.objects.map(it.name())
|
||||
} else {
|
||||
ref := method.result.schema as Reference
|
||||
ref.ref.all_after_last('/') in s.objects.map(it.name())
|
||||
}
|
||||
|
||||
return base_obj_is_param || base_obj_is_result
|
||||
}
|
||||
|
||||
fn (m ActorMethod) is_new_method() bool {
|
||||
return m.name.starts_with('new')
|
||||
}
|
||||
fn (m ActorMethod) is_get_method() bool {
|
||||
return m.name.starts_with('get')
|
||||
}
|
||||
fn (m ActorMethod) is_set_method() bool {
|
||||
return m.name.starts_with('set')
|
||||
}
|
||||
fn (m ActorMethod) is_delete_method() bool {
|
||||
return m.name.starts_with('delete')
|
||||
}
|
||||
fn (m ActorMethod) is_list_method() bool {
|
||||
return m.name.starts_with('list')
|
||||
}
|
||||
fn (m ActorMethod) is_filter_method() bool {
|
||||
return m.name.starts_with('filter')
|
||||
}
|
||||
|
||||
fn (m ActorMethod) is_crudlf_method() bool {
|
||||
return m.is_new_method() ||
|
||||
m.is_get_method() ||
|
||||
m.is_set_method() ||
|
||||
m.is_delete_method() ||
|
||||
m.is_list_method() ||
|
||||
m.is_filter_method()
|
||||
}
|
||||
|
||||
pub fn (o BaseObject) name() string {
|
||||
return if o.schema.id.trim_space() != '' {
|
||||
o.schema.id.trim_space()
|
||||
} else {o.schema.title.trim_space()}
|
||||
}
|
||||
|
||||
fn (s ActorSpecification) is_base_object_new_method(method ActorMethod) bool {
|
||||
return s.is_base_object_method(method) && method.name.starts_with('new')
|
||||
}
|
||||
|
||||
fn (s ActorSpecification) is_base_object_get_method(method ActorMethod) bool {
|
||||
return s.is_base_object_method(method) && method.name.starts_with('get')
|
||||
}
|
||||
|
||||
fn (s ActorSpecification) is_base_object_set_method(method ActorMethod) bool {
|
||||
return s.is_base_object_method(method) && method.name.starts_with('set')
|
||||
}
|
||||
|
||||
fn (s ActorSpecification) is_base_object_delete_method(method ActorMethod) bool {
|
||||
return s.is_base_object_method(method) && method.name.starts_with('delete')
|
||||
}
|
||||
|
||||
fn (s ActorSpecification) is_base_object_list_method(method ActorMethod) bool {
|
||||
return s.is_base_object_method(method) && method.name.starts_with('list')
|
||||
}
|
||||
Reference in New Issue
Block a user