Skip to content

Commit 2f558d1

Browse files
committed
Generating SQS controller with V2 works!!
1 parent 9e490dc commit 2f558d1

File tree

126 files changed

+24438
-888
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

126 files changed

+24438
-888
lines changed

apiv2/converter.go

Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
package apiv2
2+
3+
/*
4+
* This MF will help me translate a file into another file
5+
6+
SDK V2 file is a bit tricky/fancy
7+
But ig we can get this ish done quilicky lili
8+
*/
9+
import (
10+
"encoding/json"
11+
"errors"
12+
"fmt"
13+
"os"
14+
"strings"
15+
16+
"github.com/aws-controllers-k8s/code-generator/pkg/api"
17+
)
18+
19+
type API struct {
20+
Shapes map[string]Shape
21+
}
22+
23+
type Shape struct {
24+
Type string
25+
Traits map[string]interface{}
26+
MemberRefs map[string]*ShapeRef `json:"members"`
27+
MemberRef *ShapeRef `json:"member"`
28+
KeyRef ShapeRef `json:"key"`
29+
ValueRef ShapeRef `json:"value"`
30+
InputRef ShapeRef `json:"input"`
31+
OutputRef ShapeRef `json:"output"`
32+
ErrorRefs []ShapeRef `json:"errors"`
33+
}
34+
35+
type ShapeRef struct {
36+
API *API `json:"-"`
37+
Shape *Shape `json:"-"`
38+
ShapeName string `json:"target"`
39+
Traits map[string]interface{}
40+
}
41+
42+
func ConvertApiV2Shapes(modelPath string) (map[string]*api.API, error) {
43+
44+
// Read the json file
45+
file, err := os.ReadFile(modelPath)
46+
if err != nil {
47+
return nil, fmt.Errorf("error reading file: %v", err)
48+
}
49+
50+
// unmarshal the file
51+
var customAPI API
52+
err = json.Unmarshal(file, &customAPI)
53+
if err != nil {
54+
return nil, fmt.Errorf("error unmarshalling file: %v", err)
55+
}
56+
57+
serviceAlias := extractServiceAlias(modelPath)
58+
59+
newApi, err := BuildAPI(customAPI.Shapes, serviceAlias)
60+
if err != nil {
61+
return nil, fmt.Errorf("error building api: %v", err)
62+
}
63+
64+
newApi.StrictServiceId = true
65+
66+
err = newApi.Setup()
67+
if err != nil {
68+
return nil, fmt.Errorf("error setting up api: %v", err)
69+
}
70+
71+
return map[string]*api.API{
72+
serviceAlias: newApi,
73+
}, nil
74+
}
75+
76+
// This function tries to translate the API from sdk go v2
77+
// into the struct for sdk go v1
78+
func BuildAPI(shapes map[string]Shape, serviceAlias string) (*api.API, error) {
79+
80+
newApi := api.API{
81+
Metadata: api.Metadata{},
82+
Operations: map[string]*api.Operation{},
83+
Shapes: map[string]*api.Shape{},
84+
}
85+
86+
for shapeName, shape := range shapes {
87+
88+
name := removeNamePrefix(shapeName, serviceAlias)
89+
if shape.Type != "service" && shape.Type != "operation" {
90+
newShape, err := createApiShape(shape)
91+
if err != nil {
92+
return nil, err
93+
}
94+
newApi.Shapes[name] = newShape
95+
}
96+
97+
switch shape.Type {
98+
case "service":
99+
serviceId, ok := shape.Traits["aws.api#service"].(map[string]interface{})["sdkId"]
100+
if !ok {
101+
return nil, errors.New("service id not found")
102+
}
103+
newApi.Metadata.ServiceID = serviceId.(string)
104+
doc, ok := shape.Traits["smithy.api#documentation"]
105+
if !ok {
106+
return nil, errors.New("service documentation not found")
107+
}
108+
newApi.Documentation = api.AppendDocstring("", doc.(string))
109+
case "operation":
110+
newApi.Operations[name] = createApiOperation(shape, name, serviceAlias)
111+
case "structure":
112+
AddMemberRefs(newApi.Shapes[name], shape, serviceAlias)
113+
case "list":
114+
AddMemberRef(newApi.Shapes[name], name, shape, serviceAlias)
115+
case "map":
116+
AddKeyAndValueRef(newApi.Shapes[name], name, shape, serviceAlias)
117+
case "enum":
118+
AddEnumRef(newApi.Shapes[name], shape)
119+
}
120+
121+
}
122+
123+
return &newApi, nil
124+
}
125+
126+
func createApiOperation(shape Shape, name, serviceAlias string) *api.Operation {
127+
128+
newOperation := &api.Operation{
129+
Name: name,
130+
Documentation: api.AppendDocstring("", shape.Traits["smithy.api#documentation"].(string)),
131+
}
132+
133+
if hasPrefix(shape.InputRef.ShapeName, serviceAlias) {
134+
inputName := removeNamePrefix(shape.InputRef.ShapeName, serviceAlias)
135+
newOperation.InputRef = api.ShapeRef{
136+
ShapeName: inputName,
137+
}
138+
}
139+
if hasPrefix(shape.OutputRef.ShapeName, serviceAlias) {
140+
outputName := removeNamePrefix(shape.OutputRef.ShapeName, serviceAlias)
141+
newOperation.OutputRef = api.ShapeRef{
142+
ShapeName: outputName,
143+
}
144+
}
145+
146+
for _, err := range shape.ErrorRefs {
147+
newOperation.ErrorRefs = append(newOperation.ErrorRefs, api.ShapeRef{
148+
ShapeName: removeNamePrefix(err.ShapeName, serviceAlias),
149+
})
150+
}
151+
152+
return newOperation
153+
}
154+
155+
func createApiShape(shape Shape) (*api.Shape, error) {
156+
157+
isException := shape.IsException()
158+
159+
shapeType := shape.Type
160+
if shapeType == "enum" {
161+
shapeType = "string"
162+
}
163+
164+
apiShape := &api.Shape{
165+
Type: shapeType,
166+
Exception: isException,
167+
MemberRefs: make(map[string]*api.ShapeRef),
168+
MemberRef: api.ShapeRef{},
169+
KeyRef: api.ShapeRef{},
170+
ValueRef: api.ShapeRef{},
171+
Required: []string{},
172+
}
173+
174+
if isException {
175+
code, ok := shape.Traits["smithy.api#httpError"]
176+
if ok {
177+
switch code := code.(type) {
178+
case float64:
179+
apiShape.ErrorInfo = api.ErrorInfo{
180+
HTTPStatusCode: int(code),
181+
}
182+
case int:
183+
apiShape.ErrorInfo = api.ErrorInfo{
184+
HTTPStatusCode: code,
185+
}
186+
case int64:
187+
apiShape.ErrorInfo = api.ErrorInfo{
188+
HTTPStatusCode: int(code),
189+
}
190+
default:
191+
return nil, fmt.Errorf("status code type not found for exception")
192+
}
193+
}
194+
}
195+
196+
return apiShape, nil
197+
}
198+
199+
func AddMemberRefs(apiShape *api.Shape, shape Shape, serviceAlias string) {
200+
201+
var documentation string
202+
for memberName, member := range shape.MemberRefs {
203+
if !hasPrefix(member.ShapeName, serviceAlias) {
204+
continue
205+
}
206+
shapeNameClean := removeNamePrefix(member.ShapeName, serviceAlias)
207+
if member.Traits["smithy.api#documentation"] != nil {
208+
documentation = api.AppendDocstring("", member.Traits["smithy.api#documentation"].(string))
209+
}
210+
if member.IsRequired() {
211+
apiShape.Required = append(apiShape.Required, memberName)
212+
}
213+
apiShape.MemberRefs[memberName] = &api.ShapeRef{
214+
ShapeName: shapeNameClean,
215+
Documentation: documentation,
216+
}
217+
}
218+
219+
if shape.Traits["smithy.api#documentation"] != nil {
220+
documentation = api.AppendDocstring("", shape.Traits["smithy.api#documentation"].(string))
221+
}
222+
// Add the documentation to the shape
223+
apiShape.Documentation = documentation
224+
}
225+
226+
func AddMemberRef(apiShape *api.Shape, shapeName string, shape Shape, serviceAlias string) {
227+
228+
apiShape.MemberRef = api.ShapeRef{
229+
ShapeName: removeNamePrefix(shape.MemberRef.ShapeName, serviceAlias),
230+
}
231+
}
232+
233+
func AddKeyAndValueRef(apiShape *api.Shape, shapeName string, shape Shape, serviceAlias string) {
234+
235+
apiShape.KeyRef = api.ShapeRef{
236+
ShapeName: removeNamePrefix(shape.KeyRef.ShapeName, serviceAlias),
237+
}
238+
apiShape.ValueRef = api.ShapeRef{
239+
ShapeName: removeNamePrefix(shape.ValueRef.ShapeName, serviceAlias),
240+
}
241+
}
242+
243+
func AddEnumRef(apiShape *api.Shape, shape Shape) {
244+
for memberName := range shape.MemberRefs {
245+
apiShape.Enum = append(apiShape.Enum, memberName)
246+
}
247+
}
248+
249+
func (s ShapeRef) IsRequired() bool {
250+
_, ok := s.Traits["smithy.api#required"]
251+
return ok
252+
}
253+
254+
func (s Shape) IsException() bool {
255+
_, ok := s.Traits["smithy.api#error"]
256+
return ok
257+
}
258+
259+
func hasPrefix(name, alias string) bool {
260+
261+
prefix := fmt.Sprintf("com.amazonaws.%s#", alias)
262+
263+
return strings.HasPrefix(name, prefix)
264+
}
265+
266+
func removeNamePrefix(name, alias string) string {
267+
268+
toTrim := fmt.Sprintf("com.amazonaws.%s#", alias)
269+
270+
newName := strings.TrimPrefix(name, toTrim)
271+
272+
return newName
273+
}
274+
275+
func extractServiceAlias(modelPath string) string {
276+
// Split the path into parts
277+
parts := strings.Split(modelPath, "/")
278+
279+
// Get the last part
280+
lastPart := parts[len(parts)-1]
281+
282+
// Split the last part by "." to get the service alias
283+
serviceAlias := strings.Split(lastPart, ".")[0]
284+
285+
return serviceAlias
286+
}

0 commit comments

Comments
 (0)