Skip to content

Commit

Permalink
Intermediate commit
Browse files Browse the repository at this point in the history
  • Loading branch information
bdragon300 committed Dec 23, 2024
1 parent b696a02 commit 98543b3
Show file tree
Hide file tree
Showing 32 changed files with 370 additions and 291 deletions.
1 change: 0 additions & 1 deletion cmd/go-asyncapi/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,6 @@ func getPubSubVariant(cmd *GenerateCmd) (pub bool, sub bool, variant *generatePu
func getCompileOpts(opts generatePubSubArgs, isPub, isSub bool) (common.CompileOpts, error) {
//var err error
res := common.CompileOpts{
//NoEncodingPackage: opts.NoEncoding,
AllowRemoteRefs: opts.AllowRemoteRefs,
RuntimeModule: opts.RuntimeModule,
GeneratePublishers: isPub,
Expand Down
1 change: 1 addition & 0 deletions internal/asyncapi/asyncapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ func (a AsyncAPI) Compile(ctx *common.CompileContext) error {
}

func (a AsyncAPI) build(ctx *common.CompileContext) *render.AsyncAPI {
ctx.Logger.Trace("AsyncAPI root object")
res := &render.AsyncAPI{
DefaultContentType: a.DefaultContentType,
}
Expand Down
6 changes: 0 additions & 6 deletions internal/asyncapi/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,6 @@ func (c Channel) Compile(ctx *common.CompileContext) error {
return err
}
ctx.PutObject(obj)
//if v, ok := obj.(*render.Channel); ok {
// ctx.Logger.Trace("Objects", "object", obj)
// for _, protoObj := range v.ProtoChannels {
// ctx.PutObject(protoObj)
// }
//}
return nil
}

Expand Down
20 changes: 20 additions & 0 deletions internal/asyncapi/contenttype.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package asyncapi

import (
"github.com/samber/lo"
"strings"
"unicode"
)

// guessTagByContentType guesses the struct tag name by the MIME type. It returns the last
// word extracted from the content type string, e.g. for "application/xhtml+xml" it will return "xml".
func guessTagByContentType(contentType string) string {
words := strings.FieldsFunc(contentType, func(r rune) bool {
return !unicode.IsLetter(r) && !unicode.IsNumber(r)
})
if res, ok := lo.Last(words); ok {
return res
}

return contentType
}
9 changes: 2 additions & 7 deletions internal/asyncapi/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,6 @@ func (m Message) Compile(ctx *common.CompileContext) error {
return err
}
ctx.PutObject(obj)
//if v, ok := obj.(*render.Message); ok {
// ctx.Logger.Trace("ProtoObjects", "object", obj)
// for _, protoObj := range v.ProtoMessages {
// ctx.PutObject(protoObj)
// }
//}
return nil
}

Expand All @@ -64,6 +58,8 @@ func (m Message) build(ctx *common.CompileContext, messageKey string) (common.Re
}

if m.Ref != "" {
ctx.Logger.Trace("Ref", "$ref", m.Ref)

// Message is the only type of objects, that has their own root key, the key in components and can be used
// as ref in other objects at the same time (at channel.[publish|subscribe].message).
// Therefore, a message object may get to selections more than once, it's needed to handle in templates.
Expand All @@ -79,7 +75,6 @@ func (m Message) build(ctx *common.CompileContext, messageKey string) (common.Re
makeSelectable = true
}

ctx.Logger.Trace("Ref", "$ref", m.Ref)
// Always draw the promises that are located in the `messages` section
prm := lang.NewRef(m.Ref, refName, lo.Ternary(makeSelectable, lo.ToPtr(true), nil))
ctx.PutPromise(prm)
Expand Down
37 changes: 19 additions & 18 deletions internal/asyncapi/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,14 @@ func (o Object) build(ctx *common.CompileContext, flags map[common.SchemaTag]str
return &lang.GoSimple{TypeName: "any", IsInterface: true}, nil
}
if o.Ref != "" {
ctx.Logger.Trace("Ref", "$ref", o.Ref)

refName := objectKey
// Ignore the objectKey in definitions other than `components.schemas`, generate a unique name instead
if !isComponent {
refName = ctx.GenerateObjName("", "")
}

ctx.Logger.Trace("Ref", "$ref", o.Ref)
res := lang.NewRef(o.Ref, refName, lo.ToPtr(false))
ctx.PutPromise(res)
return res, nil
Expand All @@ -107,7 +108,7 @@ func (o Object) build(ctx *common.CompileContext, flags map[common.SchemaTag]str
}

if len(o.OneOf)+len(o.AnyOf)+len(o.AllOf) > 0 {
ctx.Logger.Trace("Object is union struct")
ctx.Logger.Trace("Object", "type", "union")
return o.buildUnionStruct(ctx, flags) // TODO: process other items that can be set along with oneof/anyof/allof
}

Expand All @@ -128,8 +129,7 @@ func (o Object) build(ctx *common.CompileContext, flags map[common.SchemaTag]str
ctx.Logger.Trace("Object is nullable, make it pointer")
golangType = &lang.GoPointer{Type: golangType}
}
n := golangType.Name()
_=n

return golangType, nil
}

Expand Down Expand Up @@ -163,11 +163,11 @@ func (o Object) buildGolangType(ctx *common.CompileContext, flags map[common.Sch
if typeName == "object" {
if o.XGoType != nil && !o.XGoType.V1.Embedded {
f := buildXGoType(o.XGoType)
ctx.Logger.Trace("Object is custom type", "type", f.String())
ctx.Logger.Trace("Object with custom type", "type", f.String())
return f, nil
}

ctx.Logger.Trace("Object is struct")
ctx.Logger.Trace("Object", "type", "struct")
ctx.Logger.NextCallLevel()
golangType, err = o.buildLangStruct(ctx, flags)
ctx.Logger.PrevCallLevel()
Expand All @@ -179,35 +179,35 @@ func (o Object) buildGolangType(ctx *common.CompileContext, flags map[common.Sch

if o.XGoType != nil {
f := buildXGoType(o.XGoType)
ctx.Logger.Trace("Object is a custom type", "type", f.String())
ctx.Logger.Trace("Object with custom type", "type", f.String())
return f, nil
}

switch typeName {
case "array":
ctx.Logger.Trace("Object is array")
ctx.Logger.Trace("Object", "type", "array")
ctx.Logger.NextCallLevel()
golangType, err = o.buildLangArray(ctx, flags)
ctx.Logger.PrevCallLevel()
if err != nil {
return nil, err
}
case "null", "":
ctx.Logger.Trace("Object is any")
ctx.Logger.Trace("Object", "type", "any")
golangType = &lang.GoSimple{TypeName: "any", IsInterface: true}
case "boolean":
ctx.Logger.Trace("Object is bool")
ctx.Logger.Trace("Object", "type", "bool")
aliasedType = &lang.GoSimple{TypeName: "bool"}
case "integer":
// TODO: "format:"
ctx.Logger.Trace("Object is int")
ctx.Logger.Trace("Object", "type", "int")
aliasedType = &lang.GoSimple{TypeName: "int"}
case "number":
// TODO: "format:"
ctx.Logger.Trace("Object is float64")
ctx.Logger.Trace("Object", "type", "float64")
aliasedType = &lang.GoSimple{TypeName: "float64"}
case "string":
ctx.Logger.Trace("Object is string")
ctx.Logger.Trace("Object", "type", "string")
aliasedType = &lang.GoSimple{TypeName: "string"}
default:
return nil, types.CompileError{Err: fmt.Errorf("unknown jsonschema type %q", typeName), Path: ctx.PathStackRef()}
Expand Down Expand Up @@ -262,14 +262,15 @@ func (o Object) buildLangStruct(ctx *common.CompileContext, flags map[common.Sch
var contentTypesFunc func() []string
_, isMarshal := flags[common.SchemaTagMarshal]
if isMarshal {
ctx.Logger.Trace("Object struct is marshalable")
messagesPrm := lang.NewListCbPromise[*render.Message](func(item common.CompileObject, _ []string) bool {
_, ok := item.Renderable.(*render.Message)
return ok
})
ctx.PutListPromise(messagesPrm)
contentTypesFunc = func() []string {
tagNames := lo.Uniq(lo.Map(messagesPrm.T(), func(item *render.Message, _ int) string {
return item.EffectiveContentType()
return guessTagByContentType(item.EffectiveContentType())
}))
slices.Sort(tagNames)
return tagNames
Expand Down Expand Up @@ -316,7 +317,7 @@ func (o Object) buildLangStruct(ctx *common.CompileContext, flags map[common.Sch
propName, _ := lo.Coalesce(o.AdditionalProperties.V0.XGoName, o.Title)
switch o.AdditionalProperties.Selector {
case 0: // "additionalProperties:" is an object
ctx.Logger.Trace("Object additional properties as an object")
ctx.Logger.Trace("Object additional properties", "type", "object")
ref := ctx.PathStackRef("additionalProperties")
prm := lang.NewGolangTypePromise(ref)
ctx.PutPromise(prm)
Expand All @@ -339,7 +340,7 @@ func (o Object) buildLangStruct(ctx *common.CompileContext, flags map[common.Sch
}
res.Fields = append(res.Fields, f)
case 1:
ctx.Logger.Trace("Object additional properties as boolean flag")
ctx.Logger.Trace("Object additional properties", "type", "boolean")
if o.AdditionalProperties.V1 { // "additionalProperties: true" -- allow any additional properties
valTyp := lang.GoTypeAlias{
BaseType: lang.BaseType{
Expand Down Expand Up @@ -386,13 +387,13 @@ func (o Object) buildLangArray(ctx *common.CompileContext, flags map[common.Sche

switch {
case o.Items != nil && o.Items.Selector == 0: // Only one "type:" of items
ctx.Logger.Trace("Object items (single type)")
ctx.Logger.Trace("Object items", "typesCount", "single")
ref := ctx.PathStackRef("items")
prm := lang.NewGolangTypePromise(ref)
ctx.PutPromise(prm)
res.ItemsType = prm
case o.Items == nil || o.Items.Selector == 1: // No items or Several types for each item sequentially
ctx.Logger.Trace("Object items (zero or several types)")
ctx.Logger.Trace("Object items", "typesCount", "zero or several")
valTyp := lang.GoTypeAlias{
BaseType: lang.BaseType{
OriginalName: ctx.GenerateObjName(objName, "ItemsItemValue"),
Expand Down
2 changes: 1 addition & 1 deletion internal/asyncapi/parameter.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func (p Parameter) build(ctx *common.CompileContext, parameterKey string) (commo
Fields: []lang.GoStructField{{Name: "Value", Type: prm}},
}
} else {
ctx.Logger.Trace("Parameter has no schema")
ctx.Logger.Trace("Parameter without schema")
res.Type = &lang.GoTypeAlias{
BaseType: lang.BaseType{
OriginalName: ctx.GenerateObjName(parName, ""),
Expand Down
3 changes: 0 additions & 3 deletions internal/asyncapi/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ func (s Server) Compile(ctx *common.CompileContext) error {
return err
}
ctx.PutObject(obj)
//if v, ok := obj.(*render.Server); ok {
// ctx.PutObject(v.ProtoServer)
//}
return nil
}

Expand Down
3 changes: 2 additions & 1 deletion internal/common/compile_context.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package common

import (
"fmt"
"path"
"strings"

Expand Down Expand Up @@ -39,7 +40,6 @@ type CompileOpts struct {
//MessageOpts ObjectCompileOpts
//ModelOpts ObjectCompileOpts
//ServerOpts ObjectCompileOpts
//NoEncodingPackage bool // TODO: remove in favor of selections
AllowRemoteRefs bool
RuntimeModule string
GeneratePublishers bool
Expand Down Expand Up @@ -88,6 +88,7 @@ type CompileContext struct {
}

func (c *CompileContext) PutObject(obj Renderable) {
c.Logger.Debug("Built", "object", obj.String(), "addr", fmt.Sprintf("%p", obj), "type", fmt.Sprintf("%T", obj))
c.Storage.AddObject(CompileObject{Renderable: obj, ObjectURL: c.CurrentObjectURL()})
}

Expand Down
1 change: 0 additions & 1 deletion internal/common/promise.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ type ObjectListPromise interface {
AssignList(objs []any)
Assigned() bool
FindCallback() PromiseFindCbFunc
Ref() string
}

type PromiseFindCbFunc func(item CompileObject, path []string) bool
6 changes: 0 additions & 6 deletions internal/compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,6 @@ func (c *Module) Compile(ctx *common.CompileContext) error {
if err := WalkAndCompile(ctx, reflect.ValueOf(c.parsedSpec)); err != nil {
return fmt.Errorf("spec: %w", err)
}
//if !ctx.CompileOpts.NoEncodingPackage {
// c.logger.Trace("Compile the encoding package", "specURL", c.specURL)
// if err := EncodingCompile(ctx); err != nil {
// return fmt.Errorf("encoding package: %w", err)
// }
//}
return nil
}

Expand Down
27 changes: 0 additions & 27 deletions internal/compiler/encoding.go

This file was deleted.

52 changes: 7 additions & 45 deletions internal/linker/linker.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func AssignRefs(sources map[string]ObjectSource) {
case common.PromiseOriginUser:
logger.Debug("Processing a ref", "$ref", p.Ref(), "target", res)
default:
panic(fmt.Sprintf("Unknown promise origin %v, this must not happen", p.Origin()))
panic(fmt.Sprintf("Unknown promise origin %v, this is a bug", p.Origin()))
}

p.Assign(res)
Expand Down Expand Up @@ -153,7 +153,7 @@ func resolvePromise(p common.ObjectPromise, srcSpecID string, sources map[string
}
return resolvePromise(v, tgtSpecID, sources)
case common.ObjectListPromise:
panic(fmt.Sprintf("Ref %q must point to one object, but it points to a another list promise", p.Ref()))
panic(fmt.Sprintf("Ref %q must point to one object, but it points to another list promise", p.Ref()))
case common.Renderable:
return v, true
default:
Expand All @@ -164,53 +164,15 @@ func resolvePromise(p common.ObjectPromise, srcSpecID string, sources map[string
// TODO: detect ref loops to avoid infinite recursion
func resolveListPromise(p common.ObjectListPromise, srcSpecID string, sources map[string]ObjectSource) ([]common.Renderable, bool) {
// Exclude links from selection in order to avoid duplicates in list
cb := func(obj common.CompileObject, _ []string) bool { return !isPromise(obj) }
userCallback := p.FindCallback()
if userCallback != nil {
cb = userCallback
cb := p.FindCallback()
if cb == nil {
panic("List promise must have a callback, this is a bug")
}
srcObjects := sources[srcSpecID].AllObjects()
found := lo.Filter(srcObjects, func(obj common.CompileObject, _ int) bool {
return cb(obj, obj.ObjectURL.Pointer)
})

// If we set a callback, let it decide which objects should get to promise, don't do recursive resolving
if userCallback != nil {
return lo.Map(found, func(item common.CompileObject, _ int) common.Renderable { return item.Renderable }), true
}

var results []common.Renderable
for _, obj := range found {
switch v := obj.Renderable.(type) {
case common.ObjectPromise:
if !v.Assigned() {
return results, false
}
resolved, ok := resolvePromise(v, srcSpecID, sources)
if !ok {
return results, false
}
results = append(results, resolved)
case common.ObjectListPromise:
if !v.Assigned() {
return results, false
}
resolved, ok := resolveListPromise(v, srcSpecID, sources)
if !ok {
return results, false
}
results = append(results, resolved...)
case common.Renderable:
results = append(results, v)
default:
panic(fmt.Sprintf("Found an object of unexpected type %T", v))
}
}
return results, true
}

func isPromise(obj any) bool {
_, ok1 := obj.(common.ObjectPromise)
_, ok2 := obj.(common.ObjectListPromise)
return ok1 || ok2
// Let the callaback decide which objects should be promise targets, don't do recursive resolving
return lo.Map(found, func(item common.CompileObject, _ int) common.Renderable { return item.Renderable }), true
}
Loading

0 comments on commit 98543b3

Please sign in to comment.