openrpc to actor spec base object fixes

This commit is contained in:
timurgordon
2025-01-08 02:20:52 -05:00
parent 4733e05c58
commit 038c563843
12 changed files with 455 additions and 710 deletions

View File

@@ -8,212 +8,147 @@ import os
const actor_spec = specification.ActorSpecification{
name: 'Pet Store'
description: 'A sample API for a pet store'
interfaces: [.openapi]
structure: code.Struct{}
interfaces: [.openrpc]
methods: [
specification.ActorMethod{
name: 'listPets'
name: 'list_pets'
summary: 'List all pets'
parameters: [
openrpc.ContentDescriptor{
name: 'limit'
summary: 'Maximum number of pets to return'
description: 'Maximum number of pets to return'
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'integer'
format: 'int32'
})
}
]
result: openrpc.ContentDescriptor{
name: 'result'
description: 'The response of the operation.'
schema: jsonschema.SchemaRef(jsonschema.Reference{
ref: '#/components/schemas/Pets'
parameters: [openrpc.ContentDescriptor{
name: 'limit'
description: 'How many items to return at one time (max 100)'
required: false
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'integer'
minimum: 1
})
}
errors: [
openrpc.ErrorSpec{
code: 400
message: 'Invalid request'
}
]
},
specification.ActorMethod{
name: 'createPet'
summary: 'Create a new pet'
}]
result: openrpc.ContentDescriptor{
name: 'result'
description: 'The response of the operation.'
}
errors: [
openrpc.ErrorSpec{
code: 400
message: 'Invalid input'
}
]
},
specification.ActorMethod{
name: 'getPet'
summary: 'Get a pet by ID'
parameters: [
openrpc.ContentDescriptor{
name: 'petId'
summary: 'ID of the pet to retrieve'
description: 'ID of the pet to retrieve'
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'integer'
format: 'int64'
})
}
]
result: openrpc.ContentDescriptor{
name: 'result'
description: 'The response of the operation.'
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'
parameters: [
openrpc.ContentDescriptor{
name: 'petId'
summary: 'ID of the pet to delete'
description: 'ID of the pet to delete'
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'integer'
format: 'int64'
})
}
]
result: openrpc.ContentDescriptor{
name: 'result'
description: 'The response of the operation.'
}
errors: [
openrpc.ErrorSpec{
code: 404
message: 'Pet not found'
}
]
},
specification.ActorMethod{
name: 'listOrders'
summary: 'List all orders'
result: openrpc.ContentDescriptor{
name: 'result'
description: 'The response of the operation.'
name: 'pets'
description: 'A paged array of pets'
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'array'
items: jsonschema.Items(jsonschema.SchemaRef(jsonschema.Reference{
ref: '#/components/schemas/Order'
ref: '#/components/schemas/Pet'
}))
})
}
},
specification.ActorMethod{
name: 'getOrder'
summary: 'Get an order by ID'
name: 'create_pet'
summary: 'Create a pet'
parameters: [
openrpc.ContentDescriptor{
name: 'orderId'
summary: 'ID of the order to retrieve'
description: 'ID of the order to retrieve'
name: 'newPetName'
description: 'Name of pet to create'
required: true
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'integer'
format: 'int64'
typ: 'string'
})
},
openrpc.ContentDescriptor{
name: 'newPetTag'
description: 'Pet tag to create'
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'string'
})
}
]
result: openrpc.ContentDescriptor{
name: 'result'
description: 'The response of the operation.'
schema: jsonschema.SchemaRef(jsonschema.Reference{
ref: '#/components/schemas/Order'
name: 'petId'
description: 'The ID of the created pet'
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'integer'
})
}
errors: [
openrpc.ErrorSpec{
code: 404
message: 'Order not found'
}
]
},
specification.ActorMethod{
name: 'deleteOrder'
summary: 'Delete an order by ID'
name: 'get_pet'
summary: 'Info for a specific pet'
parameters: [openrpc.ContentDescriptor{
name: 'petId'
description: 'The ID of the pet to retrieve'
required: true
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'integer'
})
}]
result: openrpc.ContentDescriptor{
name: 'pet'
description: 'The pet details'
schema: jsonschema.SchemaRef(jsonschema.Reference{
ref: '#/components/schemas/Pet'
})
}
},
specification.ActorMethod{
name: 'update_pet'
summary: 'Update a pet'
parameters: [
openrpc.ContentDescriptor{
name: 'orderId'
summary: 'ID of the order to delete'
description: 'ID of the order to delete'
name: 'petId'
description: 'The ID of the pet to update'
required: true
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'integer'
format: 'int64'
})
},
openrpc.ContentDescriptor{
name: 'updatedPetName'
description: 'New name for the pet'
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'string'
})
},
openrpc.ContentDescriptor{
name: 'updatedPetTag'
description: 'New tag for the pet'
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'string'
})
}
]
result: openrpc.ContentDescriptor{
name: 'result'
description: 'The response of the operation.'
name: 'pet'
description: 'The updated pet object'
schema: jsonschema.SchemaRef(jsonschema.Reference{
ref: '#/components/schemas/Pet'
})
}
errors: [
openrpc.ErrorSpec{
code: 404
message: 'Order not found'
}
]
},
specification.ActorMethod{
name: 'createUser'
summary: 'Create a user'
result: openrpc.ContentDescriptor{
name: 'result'
description: 'The response of the operation.'
}
name: 'delete_pet'
summary: 'Delete a pet'
parameters: [openrpc.ContentDescriptor{
name: 'petId'
description: 'The ID of the pet to delete'
required: true
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'integer'
})
}]
}
]
objects: [
specification.BaseObject{
structure: code.Struct{
name: 'Pet'
}
},
specification.BaseObject{
structure: code.Struct{
name: 'NewPet'
}
},
specification.BaseObject{
structure: code.Struct{
name: 'Pets'
}
},
specification.BaseObject{
structure: code.Struct{
name: 'Order'
}
},
specification.BaseObject{
structure: code.Struct{
name: 'User'
}
},
specification.BaseObject{
structure: code.Struct{
name: 'NewUser'
objects: [specification.BaseObject{
schema: jsonschema.Schema{
id: 'pet'
title: 'Pet'
description: 'A pet object'
typ: 'object'
properties: {
'id': jsonschema.SchemaRef(jsonschema.Schema{
typ: 'integer'
}),
'name': jsonschema.SchemaRef(jsonschema.Schema{
typ: 'string'
}),
'tag': jsonschema.SchemaRef(jsonschema.Schema{
typ: 'string'
})
}
required: ['id', 'name']
}
]
}]
}
const destination = '${os.dir(@FILE)}/testdata'

View File

@@ -2,6 +2,7 @@ module generator
import freeflowuniverse.herolib.core.code { Folder, IFile, VFile, CodeItem, File, Function, Param, Import, Module, Struct, CustomCode }
import freeflowuniverse.herolib.core.texttools
import freeflowuniverse.herolib.schemas.jsonschema.codegen {schema_to_struct}
import freeflowuniverse.herolib.baobab.specification {ActorMethod, ActorSpecification}
pub fn generate_model_file(spec ActorSpecification) !VFile {
@@ -10,6 +11,9 @@ pub fn generate_model_file(spec ActorSpecification) !VFile {
return VFile {
name: 'model'
items: spec.objects.map(CodeItem(it.structure))
items: spec.objects.map(CodeItem(
Struct {...schema_to_struct(it.schema)!
is_pub: true
}))
}
}

View File

@@ -97,11 +97,7 @@ pub fn from_openapi(spec OpenAPI) !ActorSpecification {
// Extract objects from OpenAPI components.schemas
for name, schema in spec.components.schemas {
objects << BaseObject{
structure: openapi_schema_to_struct(name, schema),
methods: []Function{}, // Add related methods if applicable
children: []Struct{}, // Add nested structures if defined
}
objects << BaseObject{schema as Schema}
}
return ActorSpecification{

View File

@@ -2,6 +2,7 @@ module specification
import freeflowuniverse.herolib.schemas.openrpc { OpenRPC, Method, ContentDescriptor, ErrorSpec }
import freeflowuniverse.herolib.schemas.jsonschema { Reference, Schema, SchemaRef }
import freeflowuniverse.herolib.core.texttools
// Helper function: Convert OpenRPC Method to ActorMethod
fn openrpc_method_to_actor_method(method Method) ActorMethod {
@@ -76,16 +77,23 @@ pub fn from_openrpc(spec OpenRPC) !ActorSpecification {
// Process methods
for method in spec.methods {
methods << openrpc_method_to_actor_method(method)
methods << openrpc_method_to_actor_method(spec.inflate_method(method))
}
// Process objects (schemas)
// structs := extract_structs_from_openrpc(spec)
// for structure in structs {
// objects << BaseObject{
// structure: structure
// }
// }
for key, schema in spec.components.schemas {
if schema is Schema {
if schema.typ == 'object' {
objects << BaseObject{
schema: Schema {...schema,
title: texttools.name_fix_pascal(key)
id: texttools.name_fix_snake(key)
}
}
}
}
}
return ActorSpecification{
name: spec.info.title

View File

@@ -5,563 +5,317 @@ import freeflowuniverse.herolib.schemas.openrpc { ContentDescriptor, ErrorSpec }
import freeflowuniverse.herolib.schemas.openapi { OpenAPI, Info, ServerSpec, Components, Operation, PathItem, PathRef }
import freeflowuniverse.herolib.schemas.jsonschema {Schema, Reference, SchemaRef}
const openapi_spec = openapi.OpenAPI{
openapi: '3.0.3'
info: openapi.Info{
title: 'Pet Store API'
description: 'A sample API for a pet store'
version: '1.0.0'
}
servers: [
openapi.ServerSpec{
url: 'https://api.petstore.example.com/v1'
description: 'Production server'
},
openapi.ServerSpec{
url: 'https://staging.petstore.example.com/v1'
description: 'Staging server'
}
]
paths: {
'/pets': openapi.PathItem{
get: openapi.Operation{
summary: 'List all pets'
operation_id: 'listPets'
parameters: [
openapi.Parameter{
name: 'limit'
in_: 'query'
description: 'Maximum number of pets to return'
required: false
schema: Schema{
typ: 'integer'
format: 'int32'
}
}
]
responses: {
'200': openapi.ResponseSpec{
description: 'A paginated list of pets'
content: {
'application/json': openapi.MediaType{
schema: Reference{
ref: '#/components/schemas/Pets'
}
}
}
}
'400': openapi.ResponseSpec{
description: 'Invalid request'
}
}
}
post: openapi.Operation{
summary: 'Create a new pet'
operation_id: 'createPet'
request_body: openapi.RequestBody{
required: true
content: {
'application/json': openapi.MediaType{
schema: Reference{
ref: '#/components/schemas/NewPet'
}
}
}
}
responses: {
'201': openapi.ResponseSpec{
description: 'Pet created'
content: {
'application/json': openapi.MediaType{
schema: Reference{
ref: '#/components/schemas/Pet'
}
}
}
}
'400': openapi.ResponseSpec{
description: 'Invalid input'
}
}
}
}
'/pets/{petId}': openapi.PathItem{
get: openapi.Operation{
summary: 'Get a pet by ID'
operation_id: 'getPet'
parameters: [
openapi.Parameter{
name: 'petId'
in_: 'path'
description: 'ID of the pet to retrieve'
required: true
schema: Schema{
typ: 'integer'
format: 'int64'
}
}
]
responses: {
'200': openapi.ResponseSpec{
description: 'A pet'
content: {
'application/json': openapi.MediaType{
schema: Reference{
ref: '#/components/schemas/Pet'
}
}
}
}
'404': openapi.ResponseSpec{
description: 'Pet not found'
}
}
}
delete: openapi.Operation{
summary: 'Delete a pet by ID'
operation_id: 'deletePet'
parameters: [
openapi.Parameter{
name: 'petId'
in_: 'path'
description: 'ID of the pet to delete'
required: true
schema: Schema{
typ: 'integer'
format: 'int64'
}
}
]
responses: {
'204': openapi.ResponseSpec{
description: 'Pet deleted'
}
'404': openapi.ResponseSpec{
description: 'Pet not found'
}
}
}
}
'/orders': openapi.PathItem{
get: openapi.Operation{
summary: 'List all orders'
operation_id: 'listOrders'
responses: {
'200': openapi.ResponseSpec{
description: 'A list of orders'
content: {
'application/json': openapi.MediaType{
schema: Schema{
typ: 'array'
items: SchemaRef(Reference{
ref: '#/components/schemas/Order'
})
}
}
}
}
}
}
}
'/orders/{orderId}': openapi.PathItem{
get: openapi.Operation{
summary: 'Get an order by ID'
operation_id: 'getOrder'
parameters: [
openapi.Parameter{
name: 'orderId'
in_: 'path'
description: 'ID of the order to retrieve'
required: true
schema: Schema{
typ: 'integer'
format: 'int64'
}
}
]
responses: {
'200': openapi.ResponseSpec{
description: 'An order'
content: {
'application/json': openapi.MediaType{
schema: Reference{
ref: '#/components/schemas/Order'
}
}
}
}
'404': openapi.ResponseSpec{
description: 'Order not found'
}
}
}
delete: openapi.Operation{
summary: 'Delete an order by ID'
operation_id: 'deleteOrder'
parameters: [
openapi.Parameter{
name: 'orderId'
in_: 'path'
description: 'ID of the order to delete'
required: true
schema: Schema{
typ: 'integer'
format: 'int64'
}
}
]
responses: {
'204': openapi.ResponseSpec{
description: 'Order deleted'
}
'404': openapi.ResponseSpec{
description: 'Order not found'
}
}
}
}
'/users': openapi.PathItem{
post: openapi.Operation{
summary: 'Create a user'
operation_id: 'createUser'
request_body: openapi.RequestBody{
required: true
content: {
'application/json': openapi.MediaType{
schema: Reference{
ref: '#/components/schemas/NewUser'
}
}
}
}
responses: {
'201': openapi.ResponseSpec{
description: 'User created'
content: {
'application/json': openapi.MediaType{
schema: Reference{
ref: '#/components/schemas/User'
}
}
}
}
}
}
}
}
components: openapi.Components{
schemas: {
'Pet': SchemaRef(Schema{
typ: 'object'
required: ['id', 'name']
properties: {
'id': SchemaRef(Schema{
typ: 'integer'
format: 'int64'
})
'name': SchemaRef(Schema{
typ: 'string'
})
'tag': SchemaRef(Schema{
typ: 'string'
})
}
})
'NewPet': SchemaRef(Schema{
typ: 'object'
required: ['name']
properties: {
'name': SchemaRef(Schema{
typ: 'string'
})
'tag': SchemaRef(Schema{
typ: 'string'
})
}
})
'Pets': SchemaRef(Schema{
typ: 'array'
items: SchemaRef(Reference{
ref: '#/components/schemas/Pet'
})
})
'Order': SchemaRef(Schema{
typ: 'object'
required: ['id', 'petId', 'quantity', 'shipDate']
properties: {
'id': SchemaRef(Schema{
typ: 'integer'
format: 'int64'
})
'petId': SchemaRef(Schema{
typ: 'integer'
format: 'int64'
})
'quantity': SchemaRef(Schema{
typ: 'integer'
format: 'int32'
})
'shipDate': SchemaRef(Schema{
typ: 'string'
format: 'date-time'
})
'status': SchemaRef(Schema{
typ: 'string'
enum_: ['placed', 'approved', 'delivered']
})
'complete': SchemaRef(Schema{
typ: 'boolean'
})
}
})
'User': SchemaRef(Schema{
typ: 'object'
required: ['id', 'username']
properties: {
'id': SchemaRef(Schema{
typ: 'integer'
format: 'int64'
})
'username': SchemaRef(Schema{
typ: 'string'
})
'email': SchemaRef(Schema{
typ: 'string'
})
'phone': SchemaRef(Schema{
typ: 'string'
})
}
})
'NewUser': SchemaRef(Schema{
typ: 'object'
required: ['username']
properties: {
'username': SchemaRef(Schema{
typ: 'string'
})
'email': SchemaRef(Schema{
typ: 'string'
})
'phone': SchemaRef(Schema{
typ: 'string'
})
}
})
}
}
}
const actor_spec = specification.ActorSpecification{
name: 'Pet Store API'
description: 'A sample API for a pet store'
interfaces: [.openapi]
const openrpc_spec = openrpc.OpenRPC{
openrpc: '1.0.0-rc1'
info: openrpc.Info{
title: 'Petstore'
license: openrpc.License{
name: 'MIT'
}
version: '1.0.0'
}
servers: [openrpc.Server{
name: 'localhost'
url: openrpc.RuntimeExpression('http://localhost:8080')
}]
methods: [
specification.ActorMethod{
name: 'listPets'
openrpc.Method{
name: 'list_pets'
summary: 'List all pets'
parameters: [
openrpc.ContentDescriptor{
name: 'limit'
summary: 'Maximum number of pets to return'
description: 'Maximum number of pets to return'
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'integer'
format: 'int32'
})
}
]
result: openrpc.ContentDescriptor{
name: 'result'
description: 'The response of the operation.'
schema: jsonschema.SchemaRef(jsonschema.Reference{
ref: '#/components/schemas/Pets'
params: [openrpc.ContentDescriptorRef(openrpc.ContentDescriptor{
name: 'limit'
description: 'How many items to return at one time (max 100)'
required: false
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'integer'
minimum: 1
})
}
errors: [
openrpc.ErrorSpec{
code: 400
message: 'Invalid request'
}
]
},
specification.ActorMethod{
name: 'createPet'
summary: 'Create a new pet'
result: openrpc.ContentDescriptor{
name: 'result'
description: 'The response of the operation.'
}
errors: [
openrpc.ErrorSpec{
code: 400
message: 'Invalid input'
}
]
},
specification.ActorMethod{
name: 'getPet'
summary: 'Get a pet by ID'
parameters: [
openrpc.ContentDescriptor{
name: 'petId'
summary: 'ID of the pet to retrieve'
description: 'ID of the pet to retrieve'
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'integer'
format: 'int64'
})
}
]
result: openrpc.ContentDescriptor{
name: 'result'
description: 'The response of the operation.'
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'
parameters: [
openrpc.ContentDescriptor{
name: 'petId'
summary: 'ID of the pet to delete'
description: 'ID of the pet to delete'
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'integer'
format: 'int64'
})
}
]
result: openrpc.ContentDescriptor{
name: 'result'
description: 'The response of the operation.'
}
errors: [
openrpc.ErrorSpec{
code: 404
message: 'Pet not found'
}
]
},
specification.ActorMethod{
name: 'listOrders'
summary: 'List all orders'
result: openrpc.ContentDescriptor{
name: 'result'
description: 'The response of the operation.'
})]
result: openrpc.ContentDescriptorRef(openrpc.ContentDescriptor{
name: 'pets'
description: 'A paged array of pets'
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'array'
items: jsonschema.Items(jsonschema.SchemaRef(jsonschema.Reference{
ref: '#/components/schemas/Order'
ref: '#/components/schemas/Pet'
}))
})
})
examples: [openrpc.ExamplePairing{
name: 'listPetExample'
description: 'List pet example'
}]
},
openrpc.Method{
name: 'create_pet'
summary: 'Create a pet'
params: [
openrpc.ContentDescriptorRef(openrpc.ContentDescriptor{
name: 'newPetName'
description: 'Name of pet to create'
required: true
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'string'
})
}),
openrpc.ContentDescriptorRef(openrpc.ContentDescriptor{
name: 'newPetTag'
description: 'Pet tag to create'
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'string'
})
})
]
result: openrpc.ContentDescriptorRef(jsonschema.Reference{
ref: '#/components/contentDescriptors/PetId'
})
examples: [openrpc.ExamplePairing{
name: 'createPetExample'
description: 'Create pet example'
}]
},
openrpc.Method{
name: 'get_pet'
summary: 'Info for a specific pet'
params: [openrpc.ContentDescriptorRef(jsonschema.Reference{
ref: '#/components/contentDescriptors/PetId'
})]
result: openrpc.ContentDescriptorRef(openrpc.ContentDescriptor{
name: 'pet'
description: 'Expected response to a valid request'
schema: jsonschema.SchemaRef(jsonschema.Reference{
ref: '#/components/schemas/Pet'
})
})
examples: [openrpc.ExamplePairing{
name: 'getPetExample'
description: 'Get pet example'
}]
},
openrpc.Method{
name: 'update_pet'
summary: 'Update a pet'
params: [
openrpc.ContentDescriptorRef(jsonschema.Reference{
ref: '#/components/contentDescriptors/PetId'
}),
openrpc.ContentDescriptorRef(openrpc.ContentDescriptor{
name: 'updatedPetName'
description: 'New name for the pet'
required: true
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'string'
})
}),
openrpc.ContentDescriptorRef(openrpc.ContentDescriptor{
name: 'updatedPetTag'
description: 'New tag for the pet'
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'string'
})
})
]
result: openrpc.ContentDescriptorRef(openrpc.ContentDescriptor{
name: 'pet'
description: 'Updated pet object'
schema: jsonschema.SchemaRef(jsonschema.Reference{
ref: '#/components/schemas/Pet'
})
})
examples: [openrpc.ExamplePairing{
name: 'updatePetExample'
description: 'Update pet example'
}]
},
openrpc.Method{
name: 'delete_pet'
summary: 'Delete a pet'
params: [openrpc.ContentDescriptorRef(jsonschema.Reference{
ref: '#/components/contentDescriptors/PetId'
})]
result: openrpc.ContentDescriptorRef(openrpc.ContentDescriptor{
name: 'success'
description: 'Boolean indicating success'
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'boolean'
})
})
examples: [openrpc.ExamplePairing{
name: 'deletePetExample'
description: 'Delete pet example'
}]
}
]
components: openrpc.Components{
content_descriptors: {
'PetId': openrpc.ContentDescriptorRef(openrpc.ContentDescriptor{
name: 'petId'
description: 'The ID of the pet'
required: true
schema: jsonschema.SchemaRef(jsonschema.Reference{
ref: '#/components/schemas/PetId'
})
})
}
schemas: {
'PetId': jsonschema.SchemaRef(jsonschema.Schema{
typ: 'integer'
minimum: 0
}),
'Pet': jsonschema.SchemaRef(jsonschema.Schema{
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']
})
}
}
}
const actor_spec = specification.ActorSpecification{
name: 'Petstore'
structure: code.Struct{}
interfaces: [.openrpc]
methods: [
specification.ActorMethod{
name: 'list_pets'
summary: 'List all pets'
parameters: [openrpc.ContentDescriptor{
name: 'limit'
description: 'How many items to return at one time (max 100)'
required: false
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'integer'
minimum: 1
})
}]
result: openrpc.ContentDescriptor{
name: 'pets'
description: 'A paged array of pets'
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'array'
items: jsonschema.Items(jsonschema.SchemaRef(jsonschema.Reference{
ref: '#/components/schemas/Pet'
}))
})
}
},
specification.ActorMethod{
name: 'getOrder'
summary: 'Get an order by ID'
name: 'create_pet'
summary: 'Create a pet'
parameters: [
openrpc.ContentDescriptor{
name: 'orderId'
summary: 'ID of the order to retrieve'
description: 'ID of the order to retrieve'
name: 'newPetName'
description: 'Name of pet to create'
required: true
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'integer'
format: 'int64'
typ: 'string'
})
},
openrpc.ContentDescriptor{
name: 'newPetTag'
description: 'Pet tag to create'
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'string'
})
}
]
result: openrpc.ContentDescriptor{
name: 'result'
description: 'The response of the operation.'
schema: jsonschema.SchemaRef(jsonschema.Reference{
ref: '#/components/schemas/Order'
name: 'petId'
description: 'The ID of the created pet'
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'integer'
})
}
errors: [
openrpc.ErrorSpec{
code: 404
message: 'Order not found'
}
]
},
specification.ActorMethod{
name: 'deleteOrder'
summary: 'Delete an order by ID'
name: 'get_pet'
summary: 'Info for a specific pet'
parameters: [openrpc.ContentDescriptor{
name: 'petId'
description: 'The ID of the pet to retrieve'
required: true
schema: jsonschema.SchemaRef(jsonschema.Reference{
ref: '#/components/schemas/PetId'
})
}]
result: openrpc.ContentDescriptor{
name: 'pet'
description: 'The pet details'
schema: jsonschema.SchemaRef(jsonschema.Reference{
ref: '#/components/schemas/Pet'
})
}
},
specification.ActorMethod{
name: 'update_pet'
summary: 'Update a pet'
parameters: [
openrpc.ContentDescriptor{
name: 'orderId'
summary: 'ID of the order to delete'
description: 'ID of the order to delete'
name: 'petId'
description: 'The ID of the pet to update'
required: true
schema: jsonschema.SchemaRef(jsonschema.Reference{
ref: '#/components/schemas/PetId'
})
},
openrpc.ContentDescriptor{
name: 'updatedPetName'
description: 'New name for the pet'
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'integer'
format: 'int64'
typ: 'string'
})
},
openrpc.ContentDescriptor{
name: 'updatedPetTag'
description: 'New tag for the pet'
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'string'
})
}
]
result: openrpc.ContentDescriptor{
name: 'result'
description: 'The response of the operation.'
name: 'pet'
description: 'The updated pet object'
schema: jsonschema.SchemaRef(jsonschema.Reference{
ref: '#/components/schemas/Pet'
})
}
errors: [
openrpc.ErrorSpec{
code: 404
message: 'Order not found'
}
]
},
specification.ActorMethod{
name: 'createUser'
summary: 'Create a user'
name: 'delete_pet'
summary: 'Delete a pet'
parameters: [openrpc.ContentDescriptor{
name: 'petId'
description: 'The ID of the pet to delete'
required: true
schema: jsonschema.SchemaRef(jsonschema.Reference{
ref: '#/components/schemas/PetId'
})
}]
result: openrpc.ContentDescriptor{
name: 'result'
description: 'The response of the operation.'
}
}
]
objects: [
specification.BaseObject{
structure: code.Struct{
name: 'Pet'
}
},
specification.BaseObject{
structure: code.Struct{
name: 'NewPet'
}
},
specification.BaseObject{
structure: code.Struct{
name: 'Pets'
}
},
specification.BaseObject{
structure: code.Struct{
name: 'Order'
}
},
specification.BaseObject{
structure: code.Struct{
name: 'User'
}
},
specification.BaseObject{
structure: code.Struct{
name: 'NewUser'
name: 'success'
description: 'Boolean indicating success'
schema: jsonschema.SchemaRef(jsonschema.Schema{
typ: 'boolean'
})
}
}
]
objects: []
}
pub fn test_from_openapi() ! {
assert from_openapi(openapi_spec)! == actor_spec
pub fn test_from_openrpc() ! {
panic(from_openrpc(openrpc_spec)!)
assert from_openrpc(openrpc_spec)! == actor_spec
}

View File

@@ -2,6 +2,7 @@ module specification
import freeflowuniverse.herolib.core.code { Struct, Function }
import freeflowuniverse.herolib.schemas.openrpc {ContentDescriptor, ErrorSpec}
import freeflowuniverse.herolib.schemas.jsonschema {Schema}
pub struct ActorSpecification {
pub mut:
@@ -33,7 +34,5 @@ pub:
pub struct BaseObject {
pub:
structure Struct @[omitempty]
methods []Function @[omitempty]
children []Struct @[omitempty]
schema Schema
}

View File

@@ -33,7 +33,7 @@ pub fn (s ActorSpecification) to_openapi() OpenAPI {
mut schemas := map[string]SchemaRef{}
for object in s.objects {
schemas[object.structure.name] = object.to_schema()
schemas[object.schema.id] = object.to_schema()
}
return OpenAPI{

View File

@@ -43,10 +43,10 @@ import freeflowuniverse.herolib.schemas.jsonschema.codegen { struct_to_schema }
pub fn (specification ActorSpecification) to_openrpc() OpenRPC {
mut schemas := map[string]SchemaRef{}
for obj in specification.objects {
schemas[obj.structure.name] = struct_to_schema(obj.structure)
for child in obj.children {
schemas[child.name] = struct_to_schema(child)
}
schemas[obj.schema.id] = obj.schema
// for child in obj.children {
// schemas[child.name] = struct_to_schema(child)
// }
}
return OpenRPC{
info: openrpc.Info{

View File

@@ -1,6 +1,6 @@
module jsonschema
type Items = SchemaRef | []SchemaRef
pub type Items = SchemaRef | []SchemaRef
pub type SchemaRef = Reference | Schema

View File

@@ -12,7 +12,6 @@ fn test_decode() ! {
mut doc_file := pathlib.get_file(path: openrpc.doc_path)!
content := doc_file.read()!
object := decode(content)!
assert object.openrpc == '1.0.0-rc1'
assert object.methods.map(it.name) == ['list_pets', 'create_pet', 'get_pet']
}

View File

@@ -0,0 +1,48 @@
module openrpc
import freeflowuniverse.herolib.schemas.jsonschema {Schema, Reference, SchemaRef, Items}
pub fn (s OpenRPC) inflate_method(method Method) Method {
return Method {
...method,
params: method.params.map(ContentDescriptorRef(s.inflate_content_descriptor(it)))
result: s.inflate_content_descriptor(method.result)
}
}
pub fn (s OpenRPC) inflate_content_descriptor(cd_ ContentDescriptorRef) ContentDescriptor {
cd := if cd_ is Reference {
s.components.content_descriptors[cd_.ref] as ContentDescriptor
} else { cd_ as ContentDescriptor }
return ContentDescriptor {
...cd,
schema: s.inflate_schema(cd.schema)
}
}
pub fn (s OpenRPC) inflate_schema(schema_ref SchemaRef) Schema {
if typeof(schema_ref).starts_with('unknown') { return Schema{}}
schema := if schema_ref is Reference {
if schema_ref.ref == '' {return Schema{}}
if !schema_ref.ref.starts_with('#/components/schemas/') {
panic('not implemented')
}
schema_name := schema_ref.ref.trim_string_left('#/components/schemas/')
s.inflate_schema(s.components.schemas[schema_name])
} else { schema_ref as Schema}
return Schema {
...schema,
items: s.inflate_items(schema.items)
}
}
pub fn (s OpenRPC) inflate_items(items Items) Items {
return if items is []SchemaRef {
Items(items.map(SchemaRef(s.inflate_schema(it))))
} else {
its := Items(SchemaRef(s.inflate_schema(items as SchemaRef)))
return its
}
}

View File

@@ -29,6 +29,7 @@ pub:
// Contact information for the exposed API.
pub struct Contact {
pub:
name string @[omitempty] // The identifying name of the contact person/organization.
email string @[omitempty] // The URL pointing to the contact information. MUST be in the format of a URL.
url string @[omitempty] // The email address of the contact person/organization. MUST be in the format of an email address.
@@ -36,6 +37,7 @@ pub struct Contact {
// License information for the exposed API.
pub struct License {
pub:
name string @[omitempty] // The license name used for the API.
url string @[omitempty] // A URL to the license used for the API. MUST be in the format of a URL.
}