diff --git a/.gitignore b/.gitignore index adf8f72..09820b0 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ # Go workspace file go.work +/swaggers diff --git a/client.kt b/client.kt new file mode 100644 index 0000000..b582858 --- /dev/null +++ b/client.kt @@ -0,0 +1,153 @@ +package client + +import io.micronaut.http.HttpResponse +import io.micronaut.http.annotation.* +import io.micronaut.http.client.annotation.Client + +@Client(value = "INPUT URL") +interface GDSClient { + + @Get(value = "/sales/dispatch/places") + fun getDispatchPlaces( + @Header authorization: String?, + ): HttpResponse> + + @Post(value = "/sales/order/{orderId}/passenger") + fun addPassenger( + @Header authorization: String?, + @PathVariable orderId: Int, + ): HttpResponse + + @Put(value = "/sales/session/open") + fun openSession( + @Header authorization: String?, + ): HttpResponse + + @Get(value = "/sales/trip/{tripId}/document/types") + fun getDocumentTypes( + @Header authorization: String?, + @PathVariable tripId: Int, + ): HttpResponse> + + @Get(value = "/sales/arrival/places") + fun getArrivalPlaces( + @Header authorization: String?, + ): HttpResponse> + + @Put(value = "/sales/order/tickets/{ticketId}/passenger") + fun updateTickerPassenger( + @Header authorization: String?, + @PathVariable ticketId: Int, + ): HttpResponse<> + + @Get(value = "/sales/order/{orderId}") + fun getOrder( + @Header authorization: String?, + @PathVariable orderId: Int, + ): HttpResponse + + @Delete(value = "/sales/order/{orderId}") + fun cancelOrder( + @Header authorization: String?, + @PathVariable orderId: Int, + ): HttpResponse + + @Post(value = "/sales/order/{orderId}/confirm/payment/by/{payForm}") + fun confirmPayment( + @Header authorization: String?, + @PathVariable orderId: Int, + @PathVariable payForm: String, + ): HttpResponse + + @Get(value = "/sales/ticket/series/{series}/number/{number}/return/calculation") + fun getReturnInfo( + @Header authorization: String?, + @PathVariable series: String, + @PathVariable number: String, + ): HttpResponse + + @Get(value = "/sales/trip/{tripId}/from/station/{dispatchStationId}/to/station/{arrivalStationId}/book/{ticketCount}") + fun bookOrder( + @Header authorization: String?, + @PathVariable tripId: String, + @PathVariable dispatchStationId: String, + @PathVariable arrivalStationId: String, + @PathVariable ticketCount: Int, + @PathVariable baggageCount: Int?, + ): HttpResponse + + @Get(value = "/settings") + fun getSettings( + ): HttpResponse + + @Post(value = "/auth/token") + fun login( + ): HttpResponse + + @Get(value = "/kassa") + fun index( + ): HttpResponse<> + + @Get(value = "/sales/dispatch/place/{placeId}/stations") + fun getDispatchStations( + @Header authorization: String?, + @PathVariable placeId: Int, + ): HttpResponse> + + @Post(value = "/sales/order/{orderId}/baggage") + fun addBaggage( + @Header authorization: String?, + @PathVariable orderId: Int, + ): HttpResponse + + @Put(value = "/sales/session/close") + fun closeSession( + @Header authorization: String?, + ): HttpResponse + + @Get(value = "/sales/trip/{tripId}/from/{dispatchStationId}/to/{arrivalStationId}/seats/free") + fun getSeatsFree( + @Header authorization: String?, + @PathVariable tripId: Int, + @PathVariable dispatchStationId: Int, + @PathVariable arrivalStationId: Int, + ): HttpResponse> + + @Get(value = "/sales/trip/{tripId}/ticket/types") + fun getTicketTypes( + @Header authorization: String?, + @PathVariable tripId: String, + ): HttpResponse> + + @Get(value = "/countries") + fun getCountries( + ): HttpResponse> + + @Get(value = "/sales/arrival/place/{placeId}/stations") + fun getArrivalStations( + @Header authorization: String?, + @PathVariable placeId: Int, + ): HttpResponse> + + @Get(value = "/sales/dispatch/station/{dispatchStationId}/arrival/place/{arrivalPlaceId}/{date}/trips") + fun getTrips( + @Header authorization: String?, + @PathVariable dispatchStationId: Int, + @PathVariable arrivalPlaceId: Int, + @PathVariable date: String, + ): HttpResponse> + + @Delete(value = "/sales/order/tickets/{ticketId}") + fun cancelTicket( + @Header authorization: String?, + @PathVariable ticketId: Int, + ): HttpResponse + + @Post(value = "/sales/ticket/{ticketId}/return") + fun returnTicket( + @Header authorization: String?, + @PathVariable ticketId: Int, + ): HttpResponse + +} + diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..bd3d9b7 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module git.3crabs.ru/VLADIMIR/from_swagger + +go 1.18 diff --git a/main.go b/main.go new file mode 100644 index 0000000..d1ef93c --- /dev/null +++ b/main.go @@ -0,0 +1,191 @@ +package main + +import ( + "encoding/json" + "fmt" + "os" + "strings" +) + +type config struct { + Openapi string `json:"openapi"` + Info struct { + Title string `json:"title"` + Description string `json:"description"` + Version string `json:"version"` + } `json:"info"` + Paths map[string]map[string]struct { + Tags []string `json:"tags"` + Summary string `json:"summary"` + OperationID string `json:"operationId"` + Parameters []struct { + Name string `json:"name"` + In string `json:"in"` + Schema property `json:"schema"` + } `json:"parameters"` + RequestBody *struct { + Content struct { + ApplicationJSON struct { + Schema property `json:"schema"` + } `json:"application/json"` + } `json:"content"` + Required bool `json:"required"` + } `json:"requestBody"` + Responses struct { + Num200 struct { + Description string `json:"description"` + Content struct { + ApplicationJSON struct { + Schema property `json:"schema"` + } `json:"application/json"` + } `json:"content"` + } `json:"200"` + } `json:"responses"` + } `json:"paths"` + Components struct { + Models map[string]struct { + Type string `json:"type"` + Properties map[string]property `json:"properties"` + } `json:"schemas"` + } `json:"components"` +} + +type property struct { + Type string `json:"type"` + Format string `json:"format"` + Nullable bool `json:"nullable"` + Ref string `json:"$ref"` + AllOf []struct { + Ref string `json:"$ref"` + } `json:"allOf"` + Items struct { + Ref string `json:"$ref"` + } `json:"items"` +} + +func (p *property) toKt() string { + sb := strings.Builder{} + if p.Type != "" { + sb.WriteString(fmt.Sprintf("%s", toMicronautKotlinType(*p))) + } + if p.Ref != "" { + sb.WriteString(fmt.Sprintf("%s", refToName(p.Ref))) + } + if len(p.AllOf) != 0 { + sb.WriteString(fmt.Sprintf("%s", refToName(p.AllOf[0].Ref))) + } + if p.Nullable { + sb.WriteString(fmt.Sprintf("?")) + } + return sb.String() +} + +func main() { + b, err := os.ReadFile("swaggers/example_1.json") + if err != nil { + panic(err) + } + config := &config{} + if err := json.Unmarshal(b, config); err != nil { + panic(err) + } + + res := toMicronautKotlin(config) + + if err := os.WriteFile("models.kt", []byte(res["models"]), 0600); err != nil { + panic(err) + } + + if err := os.WriteFile("client.kt", []byte(res["client"]), 0600); err != nil { + panic(err) + } +} + +func toMicronautKotlin(config *config) map[string]string { + sbModels := strings.Builder{} + sbModels.WriteString("package models\n\n") + for modelName, model := range config.Components.Models { + sbModels.WriteString(fmt.Sprintf("data class %s(\n", modelName)) + for name, value := range model.Properties { + sbModels.WriteString(fmt.Sprintf("\tvar %s: ", name)) + sbModels.WriteString(value.toKt()) + sbModels.WriteString(",\n") + } + sbModels.WriteString(")\n\n") + } + + sbClient := strings.Builder{} + sbClient.WriteString("package client\n\n") + sbClient.WriteString("import io.micronaut.http.HttpResponse\n") + sbClient.WriteString("import io.micronaut.http.annotation.*\n") + sbClient.WriteString("import io.micronaut.http.client.annotation.Client\n") + sbClient.WriteString("\n") + sbClient.WriteString("@Client(value = \"INPUT URL\")\n") + sbClient.WriteString("interface GDSClient {\n\n") + for path, methods := range config.Paths { + for method, v := range methods { + sbClient.WriteString(fmt.Sprintf("\t@%s(value = \"%s\")\n", toMicronautKotlinMethod(method), path)) + sbClient.WriteString(fmt.Sprintf("\tfun %s(\n", v.OperationID)) + + for _, p := range v.Parameters { + sbClient.WriteString("\t\t") + switch p.In { + case "header": + sbClient.WriteString("@Header") + case "path": + sbClient.WriteString("@PathVariable") + default: + sbClient.WriteString(fmt.Sprintf("(type %s not support)", p.In)) + } + sbClient.WriteString(fmt.Sprintf(" %s: %s,\n", p.Name, p.Schema.toKt())) + } + + // todo body and test + + sbClient.WriteString("\t") + sbClient.WriteString(fmt.Sprintf("): HttpResponse<%s>\n", v.Responses.Num200.Content.ApplicationJSON.Schema.toKt())) + sbClient.WriteString("\n") + } + } + sbClient.WriteString("}\n\n") + + return map[string]string{ + "models": sbModels.String(), + "client": sbClient.String(), + } +} + +func toMicronautKotlinType(prop property) string { + switch prop.Type { + case "string": + return "String" + case "integer": + return "Int" + case "boolean": + return "Boolean" + case "number": + return "Double" + case "array": + return fmt.Sprintf("List<%s>", refToName(prop.Items.Ref)) + } + return fmt.Sprintf("type %s not support", prop.Type) +} + +func toMicronautKotlinMethod(method string) string { + switch method { + case "get": + return "Get" + case "post": + return "Post" + case "put": + return "Put" + case "delete": + return "Delete" + } + return fmt.Sprintf("mmethod %s not support", method) +} + +func refToName(ref string) string { + arr := strings.Split(ref, "/") + return arr[len(arr)-1] +} diff --git a/models.kt b/models.kt new file mode 100644 index 0000000..eddd974 --- /dev/null +++ b/models.kt @@ -0,0 +1,202 @@ +package models + +data class CountryAVS( + var id: String?, + var name: String?, +) + +data class IdentifierDocumentAVS( + var number: String, + var series: String?, + var type: DocTypeAVS, +) + +data class SessionAVS( + var id: String, +) + +data class RegionAVS( + var name: String?, + var type: String?, + var country: CountryAVS?, + var id: String?, +) + +data class Settings( + var defaultPlaceId: String, + var defaultStationId: String, +) + +data class AreaAVS( + var name: String?, + var type: String?, + var id: String?, +) + +data class AuthRequest( + var username: String, + var password: String, + var ws: String, +) + +data class PassengerAVS( + var passenger: PassengerPartPassengerAVS, + var identifierDocument: IdentifierDocumentAVS, + var benefitDocument: BenefitDocumentAVS?, + var categoryId: Int, +) + +data class PassengerPartPassengerAVS( + var citizenship: CitizenshipAVS, + var docNum: String?, + var docSeries: String?, + var docTypeId: String?, + var gender: String, + var birthDate: String?, + var id: Int?, + var lastName: String, + var middleName: String?, + var phone: String?, + var firstName: String, +) + +data class TicketCategoryAVS( + var requiredDocTypes: List?, + var id: String, + var name: String, + var price: Double, +) + +data class TicketTypeAVS( + var id: String, + var name: String, + var requiredDocTypes: List?, +) + +data class PlaceAVS( + var region: RegionAVS?, + var area: AreaAVS?, + var id: String?, + var name: String?, + var type: String?, +) + +data class StationAVS( + var id: String?, + var name: String?, + var shortName: String?, + var address: String?, +) + +data class BusSeatAVS( + var id: String, + var name: String, + var num: Int, +) + +data class DeparturesKassa( + var arrivals: List, + var place: PlaceAVS?, + var station: StationAVS?, + var time: String?, + var tripId: String?, + var priceText: String, +) + +data class DocTypeAVS( + var id: String, + var name: String, +) + +data class AuthDTO( + var token: String?, + var refreshToken: String?, + var expireAt: Int?, +) + +data class OrderAVS( + var orderId: Int, + var tickets: List, + var expirationTime: String?, + var confirmError: String?, +) + +data class CitizenshipAVS( + var id: String, + var name: String, +) + +data class CountryCode( + var name: String, + var code: String, +) + +data class RequiredDocTypeAVS( + var id: String, + var name: String, +) + +data class TicketAVS( + var category: TicketCategoryAVS?, + var number: String?, + var passenger: PassengerPartPassengerAVS?, + var seat: BusSeatAVS?, + var series: String?, + var ticketClass: String, + var benefitDocument: BenefitDocumentAVS?, + var id: String, + var identifierDocument: IdentifierDocumentAVS?, + var payments: List?, + var status: String, +) + +data class TripKassa( + var bus: BusAVS?, + var seatsText: String, + var carrier: CarrierAVS?, + var changeSeatAllow: Boolean?, + var departures: List, + var name: String?, +) + +data class BenefitDocumentAVS( + var issuer: String?, + var number: String, + var series: String?, + var type: DocTypeAVS, + var beginDate: String?, + var endDate: String?, + var issueDate: String?, +) + +data class BusAVS( + var capacity: Int?, + var freeSeats: Int?, + var info: String?, +) + +data class CarrierAVS( + var inn: String?, + var name: String?, +) + +data class ArrivalsAVS( + var price: Int?, + var station: StationAVS?, + var time: String?, +) + +data class DocumentTypeAVS( + var id: String, + var name: String, +) + +data class TicketPaymentAVS( + var amount: Double, + var from: String?, + var group: String, + var id: String, + var name: String, + var nds: String, +) +