From 82a7575d3b57a457f383661735be597fc82a07ea Mon Sep 17 00:00:00 2001 From: Njal Karevoll Date: Thu, 6 Mar 2025 23:59:29 +0100 Subject: [PATCH 1/2] encoding/openapi: add support for openapi extension attributes in builder Signed-off-by: Njal Karevoll --- encoding/openapi/build.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/encoding/openapi/build.go b/encoding/openapi/build.go index 8074dbc8a1a..e5ec9f1d66d 100644 --- a/encoding/openapi/build.go +++ b/encoding/openapi/build.go @@ -28,6 +28,7 @@ import ( "cuelang.org/go/cue/ast" "cuelang.org/go/cue/errors" "cuelang.org/go/cue/token" + cuejson "cuelang.org/go/encoding/json" "cuelang.org/go/internal" "cuelang.org/go/internal/core/adt" ) @@ -740,6 +741,26 @@ func (b *builder) object(v cue.Value) { b.setSingle("properties", (*ast.StructLit)(properties), false) } + attr := v.Attribute("openapi") + for i := 0; i < attr.NumArgs(); i++ { + key, value := attr.Arg(i) + if key != "extension" { + continue + } + + parts := strings.SplitN(value, ":", 2) + if len(parts) != 2 { + b.failf(v, "invalid openapi extension attribute %q: %v must be in the format key:value", key, value) + } else { + extension, err := cuejson.Extract(key, []byte(parts[1])) + if err != nil { + b.failf(v, "invalid openapi extension attribute %q: %v", key, err) + } + + b.setSingle(parts[0], extension, true) + } + } + if t := v.LookupPath(cue.MakePath(cue.AnyString)); t.Exists() && (b.core == nil || b.core.items == nil) && b.checkCycle(t) { schema := b.schema(nil, cue.AnyString, t) From 184b941759c0085fa8fc093f0675d41a84062682 Mon Sep 17 00:00:00 2001 From: Njal Karevoll Date: Fri, 23 May 2025 19:48:22 +0200 Subject: [PATCH 2/2] encoding/openapi: compile extensions as cue instead of json Signed-off-by: Njal Karevoll --- encoding/openapi/build.go | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/encoding/openapi/build.go b/encoding/openapi/build.go index e5ec9f1d66d..c989400aa59 100644 --- a/encoding/openapi/build.go +++ b/encoding/openapi/build.go @@ -28,7 +28,6 @@ import ( "cuelang.org/go/cue/ast" "cuelang.org/go/cue/errors" "cuelang.org/go/cue/token" - cuejson "cuelang.org/go/encoding/json" "cuelang.org/go/internal" "cuelang.org/go/internal/core/adt" ) @@ -742,22 +741,33 @@ func (b *builder) object(v cue.Value) { } attr := v.Attribute("openapi") - for i := 0; i < attr.NumArgs(); i++ { + for i := range attr.NumArgs() { key, value := attr.Arg(i) - if key != "extension" { + if key != "extensions" { continue } - parts := strings.SplitN(value, ":", 2) - if len(parts) != 2 { - b.failf(v, "invalid openapi extension attribute %q: %v must be in the format key:value", key, value) - } else { - extension, err := cuejson.Extract(key, []byte(parts[1])) - if err != nil { - b.failf(v, "invalid openapi extension attribute %q: %v", key, err) - } + extension := v.Context().CompileString(value) + + if extension.Err() != nil { + b.failf(v, "invalid openapi extension attribute %q: %v", key, extension.Err()) + return + } - b.setSingle(parts[0], extension, true) + iter, err := extension.Fields() + if err != nil { + b.failf(v, "invalid openapi extension attribute %q: %v", key, err) + return + } + for iter.Next() { + sel := iter.Selector() + + switch node := iter.Value().Syntax(cue.Concrete(true)).(type) { + case ast.Expr: + b.setSingle(sel.Unquoted(), node, true) + default: + b.failf(v, "invalid openapi extension attribute %q: %v must be an expression", key, value) + } } }